本篇教程的视频

本篇教程的源代码

GitHub地址:

查看源代码

那么这一篇教程我们来讲树的世界生成,前面已经讲过了TreeFeatures这个类

那么今天讲世界生成还要涉及一个TreePlacements,这个是树的放置特征,
意思就是这些树是以怎样的方式放置在世界中的

这里我们就来看看TreePlacements

1
public static final ResourceKey<PlacedFeature> OAK_CHECKED = PlacementUtils.createKey("oak_checked");

还是以橡木相关的内容为例,这里有一个放置特征的注册键

PlacementUtils.createKey方法同样是一个公共方法,但我们使用时还得带上模组的命名空间

再往下翻就能看到一个bootstrap方法,那还是用来数据生成的

1
2
3
public static void bootstrap(BootstapContext<PlacedFeature> pContext) {
...
}

这里面我们就看和橡木相关的内容

1
2
3
4
5
HolderGetter<ConfiguredFeature<?, ?>> holdergetter = pContext.lookup(Registries.CONFIGURED_FEATURE);

Holder<ConfiguredFeature<?, ?>> holder2 = holdergetter.getOrThrow(TreeFeatures.OAK);

PlacementUtils.register(pContext, OAK_CHECKED, holder2, PlacementUtils.filteredByBlockSurvival(Blocks.OAK_SAPLING));

首先先看第一个holdergetter,这个方法就是获取注册键为Registries.CONFIGURED_FEATURE的注册表

然后holder2则是获取注册表中,注册键为TreeFeatures.OAK的注册表条目

最后,用PlacementUtils.register方法则是注册一个放置特征

PlacementUtils.register方法有三个参数,第一个是注册键,第二个是注册表条目,第三个是放置条件

不过我们实际写的时候,第三个参数是直接用植被的放置特征相关的方法来写的

这里我多提一嘴,按照上面的注册键继续深挖下去,我们就能看到它在VegetationFeaturesbootstrap方法中也被调用了

植被这一大块也是有自己的构造特征放置特征的,稍微捋一下,植被是很多种植物组合在一起形成的

比如繁花森林黑森林等等,而我们写的单个的树或者其他东西,它是植被中的一部分,所以深挖下去还能了解更多东西

不过我们这里就不展开讲了,感兴趣的同学可以自行研究

注册世界生成

放置特征

这里我们来创建ModPlacedFeatures类,用来注册放置特征

1
2
3
public class ModPlacedFeatures {

}

同样的,我们还是先写一个注册键

1
2
3
4
5
public static final ResourceKey<PlacedFeature> ICE_ETHER_TREE_PLACED_KEY = registerKey("ice_ether_tree_placed");

private static ResourceKey<PlacedFeature> registerKey(String name) {
return ResourceKey.create(Registries.PLACED_FEATURE, ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, name));
}

同样的,registerKey方法也是用了原版的方法,但加上了模组的命名空间

当然,为了与前面的构造特征有所区分,我们这里注册名上可以加上一个placed

然后就是写一个bootstrap方法

1
2
3
public static void bootstrap(BootstapContext<PlacedFeature> context) {

}

参数上与原版的bootstrap方法一致

1
HolderGetter<ConfiguredFeature<?, ?>> holdergetter = context.lookup(Registries.CONFIGURED_FEATURE);

获取注册键为Registries.CONFIGURED_FEATURE的注册表

1
2
3
4
5
PlacementUtils.register(context, ICE_ETHER_TREE_PLACED_KEY,
holdergetter.getOrThrow(ModConfiguredFeatures.ICE_ETHER_TREE_KEY),
VegetationPlacements.treePlacement(
PlacementUtils.countExtra(2, 0.1f, 2),
ModBlocks.ICE_ETHER_TREE_SAPLING.get()));

然后我们就直接用PlacementUtils.register来注册放置特征

第一个参数是注册键,第二个参数是注册表条目,第三个参数是放置条件

这里第三个参数我们用了VegetationPlacements.treePlacement方法,
PlacementUtils.countExtra则是用来修改生成的数量,以区块为单位

第一个参数是一个区块中基本的生成数量,第二个是额外生成的概率,第三个是额外生成的数量

后面就传入我们先前写的树苗方块即可

群系修改

虽然我们已经配置好了树的放置特征,但它现在还不会生成在世界中,因为原版的群系生成已经定死了

我们需要改群系的设置,这里我们借助Forge提供的API来实现

接下来我们创建一个ModBiomeModifiers类,这个类未来也用得到(比如矿石、花草的世界生成等)

1
2
3
public class ModBiomeModifiers {

}

然后先注册键起手

1
2
3
4
5
public static final ResourceKey<BiomeModifier> ADD_ICE_ETHER_TREE = registerKey("add_ice_ether_tree");

private static ResourceKey<BiomeModifier> registerKey(String name) {
return ResourceKey.create(ForgeRegistries.Keys.BIOME_MODIFIERS, ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, name));
}

再来一个bootstrap方法

1
2
3
4
5
6
7
8
9
10
public static void bootstrap(BootstapContext<BiomeModifier> context) {
HolderGetter<PlacedFeature> placedFeatures = context.lookup(Registries.PLACED_FEATURE);
HolderGetter<Biome> biomes = context.lookup(Registries.BIOME);

context.register(ADD_ICE_ETHER_TREE, new ForgeBiomeModifiers.AddFeaturesBiomeModifier(
HolderSet.direct(biomes.getOrThrow(Biomes.PLAINS), biomes.getOrThrow(Biomes.FOREST)),
HolderSet.direct(placedFeatures.getOrThrow(ModPlacedFeatures.ICE_ETHER_TREE_PLACED_KEY)),
GenerationStep.Decoration.VEGETAL_DECORATION
));
}

在这里面我们用ForgeBiomeModifiers.AddFeaturesBiomeModifier来添加一个生物群系修改器

当然这种做法是会影响原版已经配置的地物生成,不过关系不大

第一个参数是选择生成的生物群系,我们选择了平原森林

第二个参数则是我们的放置特征的注册键

第三个参数是生成阶段,这里我们用了GenerationStep.Decoration.VEGETAL_DECORATION,也就是在植被生成阶段,加入我们的树

数据生成

和前面一样,我们要配置数据生成

ModWorldGenProvider

我们在之前的BUILDER字段下,添加两行代码

1
2
3
4
public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
.add(Registries.CONFIGURED_FEATURE, ModConfiguredFeatures::bootstrap)
.add(Registries.PLACED_FEATURE, ModPlacedFeatures::bootstrap)
.add(ForgeRegistries.Keys.BIOME_MODIFIERS, ModBiomeModifiers::bootstrap);

测试

随后我们就可以进行数据生成,同样它会在数据文件夹中的world_gen/placed_feature下生成一个树的放置特征文件

然后我们就可以在游戏中测试了,在平原和森林中,我们就可以看到我们的树了