Skip to main content
Version: 1.21.4

生物群系修改器(Biome Modifiers)

生物群系修改器(Biome Modifiers)是一套数据驱动的系统,允许你更改生物群系的许多方面,包括注入或移除已放置特征(PlacedFeatures)、添加或移除生物生成、改变气候设置,以及调整植被和水的颜色。NeoForge 提供了多种默认的生物群系修改器,能够覆盖绝大多数玩家和模组开发者的常见需求。

推荐阅读章节:

应用生物群系修改器(Applying Biome Modifiers)

要让 NeoForge 在游戏中加载一个生物群系修改器的 JSON 文件,需要将该文件放在模组资源目录下的 data/<modid>/neoforge/biome_modifier/<path>.json 文件夹内,或者放在一个 数据包 中。之后,当 NeoForge 加载这个生物群系修改器时,会读取其中的指令,并在世界加载时将描述的修改应用到所有目标生物群系。如果模组已经存在相关的生物群系修改器,可以通过在相同位置和名称下放置新的 JSON 文件(来自数据包)来覆盖它。

你可以手动创建 JSON 文件,具体格式可参考 “内置的 NeoForge 生物群系修改器” 章节中的示例,或者按照 “数据生成生物群系修改器” 章节的方法进行数据生成。

内置的 NeoForge 生物群系修改器(Built-in Biome Modifiers)

这些生物群系修改器由 NeoForge 注册,任何人都可以直接使用。

None

这个生物群系修改器不会进行任何操作,也不会产生任何修改。整合包作者和玩家可以在数据包中使用它,通过用下方的 JSON 覆盖模组的生物群系修改器 JSON,从而禁用对应的生物群系修改功能。

{
"type": "neoforge:none"
}

添加特性(Add Features)

这种生物群系修饰器类型会向生物群系中添加 PlacedFeature(已放置特性,例如树木或矿石),使其能够在世界生成时出现。该修饰器需要指定要添加特性的生物群系的 id 或标签(tag),要添加到选定生物群系的 PlacedFeature 的 id 或标签,以及特性将在其中生成的 GenerationStep.Decoration(生成阶段装饰)。

{
"type": "neoforge:add_features",
// 可以是单个生物群系 id,例如 "minecraft:plains",
// 也可以是生物群系 id 列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 或者是生物群系标签(tag),例如 "#c:is_overworld"。
"biomes": "#namespace:your_biome_tag",
// 可以是单个已放置特性(placed feature)id,例如 "examplemod:add_features_example",
// 也可以是已放置特性 id 列表,例如 ["examplemod:add_features_example", "minecraft:ice_spike", ...],
// 或者是已放置特性标签(tag),例如 "#examplemod:placed_feature_tag"。
"features": "namespace:your_feature",
// 有效的枚举名请参见代码中的 GenerationStep.Decoration 枚举。
// 后文的装饰阶段(decoration step)部分也列出了所有可用的取值供参考。
"step": "underground_ores"
}
warning

当你向生物群系中添加原版的 PlacedFeature(放置特性)时需要格外小心,因为这可能会导致所谓的特性循环冲突(feature cycle violation):即两个生物群系在同一 GenerationStep(生成阶段)中拥有同样的两个特性,但顺序不同,这会导致崩溃。出于类似原因,同一个 PlacedFeature 不应被用于多个生物群系修改器。

原版的 PlacedFeature 可以在生物群系的 JSON 文件中引用,或通过生物群系修改器添加,但不能两者兼用。如果你确实需要这样做,最简单的解决办法是将原版 PlacedFeature 复制到你自己的命名空间下,从而避免这些问题。

移除特性(Remove Features)

这种类型的生物群系修改器(biome modifier)可以从生物群系中移除特性(如树木或矿石),使其在世界生成时不再出现。该修改器需要指定要移除特性的生物群系的 id 或标签(tag)、要移除的 PlacedFeature 的 id 或标签,以及这些特性将被移除的 GenerationStep.Decoration 阶段。

{
"type": "neoforge:remove_features",
// 可以是生物群系 ID,例如 "minecraft:plains",
// 也可以是生物群系 ID 列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 或者是生物群系标签(tag),例如 "#c:is_overworld"。
"biomes": "#namespace:your_biome_tag",
// 可以是已放置特性(placed feature)的 ID,例如 "examplemod:add_features_example",
// 也可以是已放置特性 ID 列表,例如 ["examplemod:add_features_example", "minecraft:ice_spike", ...],
// 或者是已放置特性标签,例如 "#examplemod:placed_feature_tag"。
"features": "namespace:problematic_feature",
// 可选字段,指定要移除特性的 GenerationStep(生成阶段),也可以是 GenerationStep 列表。
// 如果省略,默认为所有 GenerationStep。
// 有效的枚举名称请参见代码中的 GenerationStep.Decoration 枚举。
// 本文稍后在装饰阶段部分也会列出所有可用的值以供参考。
"steps": ["underground_ores", "underground_decoration"]
}

添加生物生成(Add Spawns)

另请参阅 生物实体/自然生成

这种生物群系修改器(biome modifier)类型可以向生物群系添加实体(entity)生成。该修改器接收实体生成要添加到的生物群系的 ID 或标签(tag),以及要添加的实体的 SpawnerData。每个 SpawnerData 包含实体的 ID、生成权重(spawn weight)、以及每次生成时的最小/最大实体数量。

note

如果你是一名模组开发者,并且添加了一个新的实体(entity),请确保为该实体注册了生成限制(spawn restriction),方法是注册到 RegisterSpawnPlacementsEvent。生成限制用于确保实体能安全地生成在地面或水中。如果你没有注册生成限制,你的实体可能会在空中生成,掉落并死亡。

{
"type": "neoforge:add_spawns",
// 可以是生物群系(biome)的 id,例如 "minecraft:plains",
// 或一个生物群系 id 列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 也可以是生物群系标签(tag),如 "#c:is_overworld"。
"biomes": "#namespace:biome_tag",
// 可以是单个对象,也可以是对象列表。
"spawners": [
{
"type": "namespace:entity_type", // 要生成的实体类型(entity type)的 id
"weight": 100, // 非负整数,生成权重
"minCount": 1, // 正整数,最小生成组数
"maxCount": 4 // 正整数,最大生成组数
},
{
"type": "minecraft:ghast",
"weight": 1,
"minCount": 5,
"maxCount": 10
}
]
}

移除生成(Remove Spawns)

此类生物群系修改器(biome modifier)用于从生物群系中移除实体的生成。该修改器需要传入要移除实体生成的生物群系 id 或标签(tag),以及要移除的实体类型(EntityType)的 id 或标签。

{
"type": "neoforge:remove_spawns",
// 可以是生物群系(biome)的 id,例如 "minecraft:plains",
// 也可以是生物群系 id 的列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 还可以是生物群系标签(biome tag),例如 "#c:is_overworld"。
"biomes": "#namespace:biome_tag",
// 可以是实体类型(entity type)的 id,例如 "minecraft:ghast",
// 也可以是实体类型 id 的列表,例如 ["minecraft:ghast", "minecraft:skeleton", ...],
// 还可以是实体类型标签(entity type tag),例如 "#minecraft:skeletons"。
"entity_types": "#namespace:entitytype_tag"
}

添加生成消耗(Add Spawn Costs)

允许为生物群系(biome)添加新的生成消耗(spawn costs)。生成消耗是一种较新的机制,用于让生物(mob)在生物群系中更分散地生成,从而减少扎堆现象。其原理是,每个实体会释放出一个 charge(电荷),这个电荷会在实体周围叠加,如果附近有多个实体,则它们的电荷会相加。当尝试生成新的实体时,生成算法会查找某个位置,使得该位置的总 charge 字段乘以新生成实体的 charge 值后,小于该实体的 energy_budget(能量预算)。这种机制是更高级的生物生成方式,因此建议参考灵魂沙峡谷(Soul Sand Valley)生物群系(该机制的典型应用者)中的现有参数。

该修改器(modifier)需要提供要添加生成消耗的生物群系 id 或标签(tag),要添加生成消耗的实体类型(EntityType)id 或标签,以及该实体的 MobSpawnSettings.MobSpawnCostMobSpawnCost 包含能量预算(energy budget),它表示在每个生成位置,基于每个实体生成时所提供的电荷,最多可以生成多少实体。

note

如果你是一个添加新实体(entity)的模组开发者,请确保你的实体已经在 RegisterSpawnPlacementsEvent 中注册了生成限制(spawn restriction)。

{
"type": "neoforge:add_spawn_costs",
// 可以是一个生物群系(biome)的 ID,例如 "minecraft:plains",
// 也可以是一个生物群系 ID 的列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 或者是一个生物群系标签(biome tag),例如 "#c:is_overworld"。
"biomes": "#namespace:biome_tag",
// 可以是一个实体类型(entity type)的 ID,例如 "minecraft:ghast",
// 也可以是实体类型 ID 的列表,例如 ["minecraft:ghast", "minecraft:skeleton", ...],
// 或者是一个实体类型标签(entity type tag),例如 "#minecraft:skeletons"。
"entity_types": "#minecraft:skeletons",
"spawn_cost": {
// 能量预算(energy budget)
"energy_budget": 1.0,
// 每个实体从预算中消耗的能量(charge)
"charge": 0.1
}
}

移除生成消耗(Remove Spawn Costs)

允许你从某个生物群系(biome)中移除生成消耗(spawn cost)。生成消耗是一种较新的机制,用于让生物在群系中分散生成,从而减少聚集。此修改器(modifier)需要传入要移除生成消耗的生物群系的 ID 或标签(tag),以及要移除生成消耗的实体类型(EntityType)的 ID 或标签。

{
"type": "neoforge:remove_spawn_costs",
// 可以是一个生物群系 ID,例如 "minecraft:plains",
// 也可以是一个生物群系 ID 列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 或者是一个生物群系标签(tag),如 "#c:is_overworld"。
"biomes": "#namespace:biome_tag",
// 可以是一个实体类型 ID,例如 "minecraft:ghast",
// 也可以是一个实体类型 ID 列表,例如 ["minecraft:ghast", "minecraft:skeleton", ...],
// 或者是一个实体类型标签(tag),如 "#minecraft:skeletons"。
"entity_types": "#minecraft:skeletons"
}

添加传统地形切割器(Add Legacy Carvers)

这种生物群系修饰器类型允许向生物群系添加地形切割器(carver)洞穴和峡谷。这些机制用于洞穴生成,属于洞穴与悬崖更新(Caves and Cliffs)之前的旧系统。它无法向生物群系添加噪声洞穴(noise caves),因为噪声洞穴属于特定的基于噪声的区块生成器系统,并不实际绑定到生物群系上。

    {
"type": "neoforge:add_carvers",
// 可以是一个生物群系 ID,例如 "minecraft:plains",
// 也可以是一个生物群系 ID 列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 或者是一个生物群系标签(tag),如 "#c:is_overworld"。
"biomes": "minecraft:plains",
// 可以是一个地形切割器(carver)ID,例如 "examplemod:add_carvers_example",
// 也可以是一个地形切割器 ID 列表,例如 ["examplemod:add_carvers_example", "minecraft:canyon", ...],
// 或者是一个地形切割器标签(tag),如 "#examplemod:configured_carver_tag"。
"carvers": "examplemod:add_carvers_example"
}

移除传统地形雕刻器(Removing Legacy Carvers)

这种生物群系修改器(biome modifier)类型允许你从生物群系(biome)中移除传统的地形雕刻器洞穴和峡谷(carver caves and ravines)。这些雕刻器用于洞穴生成,属于洞穴与山崖(Caves and Cliffs)更新之前的旧机制。它无法移除噪声洞穴(noise caves),因为噪声洞穴已经集成在维度(dimension)的噪声设置系统中,并不直接关联到生物群系。

{
"type": "neoforge:remove_carvers",
// 可以是一个生物群系 id,例如 "minecraft:plains",
// 也可以是一个生物群系 id 列表,例如 ["minecraft:plains", "minecraft:badlands", ...],
// 或者是一个生物群系标签(tag),如 "#c:is_overworld"。
"biomes": "minecraft:plains",
// 可以是一个地形雕刻器(carver)id,例如 "examplemod:add_carvers_example",
// 也可以是一个雕刻器 id 列表,例如 ["examplemod:add_carvers_example", "minecraft:canyon", ...],
// 或者是一个雕刻器标签,如 "#examplemod:configured_carver_tag"。
"carvers": "examplemod:add_carvers_example"
}

装饰步骤可用的取值(Available Values for Decoration Steps)

许多前述 JSON 文件中的 stepsteps 字段,指的是 GenerationStep.Decoration 枚举(enum)。该枚举按如下顺序列出了所有步骤,这也是游戏在世界生成(worldgen)时所使用的顺序。请尽量将特性(feature)放在最适合它们的步骤中。

步骤(Step)描述(Description)
raw_generation最先执行。用于生成特殊的地形类特性,例如小型末地岛。
lakes专门用于生成类似池塘的地形特性,如熔岩湖。
local_modifications用于对地形进行局部修改,例如晶洞、冰山、巨石或溶洞石笋。
underground_structures用于生成小型地下结构类特性,如地牢或化石。
surface_structures用于仅在地表生成的小型结构类特性,如沙漠井。
strongholds专门用于要塞(Stronghold)结构。在未修改的 Minecraft 中,这里不会添加任何特性。
underground_ores本阶段添加所有矿石和矿脉,包括金矿、泥土、花岗岩等。
underground_decoration通常用于装饰洞穴。例如石笋簇和幽匿脉(Sculk Vein)会在此阶段生成。
fluid_springs小型熔岩瀑布和瀑布等特性会在此阶段生成。
vegetal_decoration几乎所有植物(花、树、藤蔓等)都会在此阶段添加。
top_layer_modification最后执行。用于在寒冷生物群系的地表放置雪和冰。

创建自定义生物群系修改器(Custom Biome Modifiers)

BiomeModifier 的实现(Implementation)

在底层,生物群系修改器(Biome Modifiers)由三个部分组成:

  • 数据包注册BiomeModifier,用于修改生物群系构建器(biome builder)。
  • 静态注册MapCodec,用于对修改器进行编码和解码。
  • 构建 BiomeModifier 的 JSON 文件,其中使用注册的 MapCodec 的 id 作为可索引类型。

一个 BiomeModifier 包含两个方法:#modify#codecmodify 方法接收当前 BiomeHolder,当前的 BiomeModifier.Phase,以及要修改的生物群系构建器。每个 BiomeModifier 会在每个 Phase 阶段被调用一次,以便有序地对生物群系进行特定的修改:

阶段(Phase)描述(Description)
BEFORE_EVERYTHING用于所有需要在标准阶段之前运行的内容。
ADD添加特性、生成生物等。
REMOVE移除特性、移除生成生物等。
MODIFY修改单个数值(例如气候、颜色等)。
AFTER_EVERYTHING用于所有需要在标准阶段之后运行的内容。
所有的 BiomeModifier 都包含一个 type 键,用于引用该 BiomeModifier 所用 MapCodec 的 id。codec 接收一个用于编码和解码 modifier 的 MapCodec。这个 MapCodec静态注册的,其 id 会被用作 BiomeModifiertype
public record ExampleBiomeModifier(HolderSet<Biome> biomes, int value) implements BiomeModifier {

@Override
public void modify(Holder<Biome> biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) {
if (phase == /* 选择最符合你想要修改内容的阶段 */) {
// 修改 'builder',并检查该生物群系自身的任何信息
}
}

@Override
public MapCodec<? extends BiomeModifier> codec() {
return EXAMPLE_BIOME_MODIFIER.get();
}
}

// 在某个注册类中
private static final DeferredRegister<MapCodec<? extends BiomeModifier>> BIOME_MODIFIERS =
DeferredRegister.create(NeoForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, MOD_ID);

public static final Supplier<MapCodec<ExampleBiomeModifier>> EXAMPLE_BIOME_MODIFIER =
BIOME_MODIFIERS.register("example_biome_modifier", () -> RecordCodecBuilder.mapCodec(instance ->
instance.group(
Biome.LIST_CODEC.fieldOf("biomes").forGetter(ExampleBiomeModifier::biomes),
Codec.INT.fieldOf("value").forGetter(ExampleBiomeModifier::value)
).apply(instance, ExampleBiomeModifier::new)
));

通过数据生成(Datagen)创建生物群系修改器(Biome Modifiers)

可以通过数据生成,为 BiomeModifier 创建 JSON 文件,只需将 RegistrySetBuilder 传递给 DatapackBuiltinEntriesProvider。生成的 JSON 会被放置在 data/<modid>/neoforge/biome_modifier/<path>.json 路径下。

关于 RegistrySetBuilderDatapackBuiltinEntriesProvider 的详细用法,请参阅数据包注册表的数据生成相关文章。

// 为我们的 BiomeModifier 定义 ResourceKey(资源键)。
public static final ResourceKey<BiomeModifier> EXAMPLE_MODIFIER = ResourceKey.create(
NeoForgeRegistries.Keys.BIOME_MODIFIERS, // 该键所对应的注册表
ResourceLocation.fromNamespaceAndPath(MOD_ID, "example_modifier") // 注册表名称
);

// BUILDER 是传递给 DatapackBuiltinEntriesProvider 的 RegistrySetBuilder
// 在 `GatherDataEvent` 的监听器中使用。
BUILDER.add(NeoForgeRegistries.Keys.BIOME_MODIFIERS, bootstrap -> {
// 查询所有需要的注册表。
// 静态注册表只有在需要获取标签数据时才需要查询。
HolderGetter<Biome> biomes = bootstrap.lookup(Registries.BIOME);

// 注册生物群系修改器。
bootstrap.register(EXAMPLE_MODIFIER,
new ExampleBiomeModifier(
biomes.getOrThrow(Tags.Biomes.IS_OVERWORLD),
20
)
);
});

这样会生成如下的 JSON 文件:

// 在 data/examplemod/neoforge/biome_modifier/example_modifier.json 中
{
// 修饰器的 MapCodec 的注册表(Registry)键
"type": "examplemod:example_biome_modifier",
// 所有额外的设置都应用在根对象上
"biomes": "#c:is_overworld",
"value": 20
}

目标为可能不存在的生物群系(Biome)

有时候,生物群系修饰器(biome modifier)需要作用于一个并不总是存在于游戏中的生物群系(biome)。如果修饰器直接指定了一个未注册的生物群系,那么在世界加载时就会导致崩溃。为了解决这个问题,可以创建一个生物群系标签(biome tag),并通过将 required 设置为 false,把目标生物群系作为一个可选的标签项(tag entry)添加进去。示例如下:

{
"replace": false,
"values": [
{
"id": "minecraft:pale_garden",
"required": false
}
]
}

使用这样的生物群系标签作为生物群系修饰器的目标时,如果该生物群系没有被注册,就不会导致崩溃。其中一个典型用例就是 Pale Garden 生物群系:它只会在 1.21.3 版本中启用 Winter Drop 数据包(datapack)时才会生成,否则在生物群系注册表(biome registry)中根本不存在。另一个用例是兼容模组生物群系:即使添加这些生物群系的模组没有安装,修饰器依然能够正常工作。

要为生物群系标签的数据生成(datagen)生成可选项,数据生成代码大致如下:

// 在 TagsProvider<Biome> 的子类中
// 假设我们有一个 TagKey<Biome> 类型的 OPTIONAL_BIOMES_TAG
@Override
protected void addTags(HolderLookup.Provider registries) {
this.tag(OPTIONAL_BIOMES_TAG)
// 必须是代表注册对象(registry object)的 ResourceLocation
.addOptional(WinterDropBiomes.PALE_GARDEN.location());
}

数据生成 数据包数据生成 数据包 数据包注册表 自然生成 注册方法