本篇教程的视频

(待发布)

本篇教程的源代码

(待发布)

本篇教程目标

使用TerraBlender为模组添加生物群系

准备工作

因为自Minecraft的世界生成大改以后,直接按照原版的方法添加生物群系会相当麻烦,所以我们使用第三方的API来添加生物群系

这里我们使用TerraBlender来添加生物群系,它的官方GitHub地址是TerraBlender

而要使用TerraBlender,我们需要将其添加为我们模组的依赖

build.gradle中加入依赖,先加入maven仓库

1
2
3
repositories {
maven { url = 'https://maven.minecraftforge.net/' }
}

然后是具体的依赖和版本

1
2
3
dependencies {
modImplementation 'com.github.glitchfiend:TerraBlender-fabric:1.20.1-3.0.1.10'
}

版本得改成和你开发的模组版本一致的,具体的版本号到相应的模组站去找

然后重载Gradle,让它下载依赖,运行完之后再跑一下genSources,让它下载源代码

添加生物群系

创建一堆类

Gradle在下载依赖的时候,我们先创建一些类

创建ModBiomes类

这个类用于生物群系的注册

1
2
3
public class ModBiomes {

}

创建ModOverworldRegion类

这个类用于注册Overworld的生物群系

1
2
3
public class ModOverworldRegion {

}

创建ModTerraBlenderAPI类

这个类用于TerraBlenderAPI的使用

1
2
3
public class ModTerraBlenderAPI {

}

创建ModMaterialRules类

这个类用于指定生物群系表面的方块类型

1
2
3
public class ModMaterialRules {

}

其实上面的这一堆东西,TerraBlender的仓库里面都有,可以参考它的示例代码

ModTerraBlenderAPI

那么当Gradle下载完依赖之后,我们就可以开始写代码了

首先是ModTerraBlenderAPI这个类,我们要实现TerraBlenderApi这个接口

1
2
3
4
5
6
public class ModTerraBlenderAPI implements TerraBlenderApi {
@Override
public void onTerraBlenderInitialized() {

}
}

这里是要重写onTerraBlenderInitialized这个方法,不过里面的东西我们待会再去写

记得将这个类加入到fabirc.mod.json文件中的entrypoints

1
2
3
4
5
6
"entrypoints": {
...
"terrablender": [
"com.besson.tutorial.world.biome.ModTerraBlenderAPI"
]
}

ModBiomes

我们这里先来写ModBiomes这个类,这个类用于生物群系的注册

我们直接在这个类中定义新的生物群系(源代码这里就不讲解了,可以去看看原版的生物群系是怎么注册的)

1
2
public static final RegistryKey<Biome> DIAMOND_BIOME = RegistryKey.of(RegistryKeys.BIOME,
new Identifier(TutorialModRe.MOD_ID, "diamond_biome"));

那么首先是写一个注册键,这个键是用于注册生物群系的,这里我们写一个钻石大陆的生物群系

接下来我们写globalOverWorldGeneration方法,这个方法是用于编写生物群系的生成规则,一些构造

1
2
3
4
5
6
7
8
public static void globalOverWorldGeneration(GenerationSettings.LookupBackedBuilder builder) {
DefaultBiomeFeatures.addLandCarvers(builder);
DefaultBiomeFeatures.addAmethystGeodes(builder);
DefaultBiomeFeatures.addDungeons(builder);
DefaultBiomeFeatures.addMineables(builder);
DefaultBiomeFeatures.addSprings(builder);
DefaultBiomeFeatures.addFrozenTopLayer(builder);
}

这里我们添加了一些原版的生物群系的构造

addLandCarvers是添加地形的构造

addAmethystGeodes是添加紫晶石洞穴的构造

addDungeons是添加地牢的构造

addMineables是添加矿物的构造

addSprings是添加地下水的构造

addFrozenTopLayer是添加冰层的构造(如果有高山的话)

再接下来我们写diamondBiome方法,这个方法是用于注册钻石大陆的生物群系

1
2
3
4
5
6
7
private static Biome diamondBiome(Registerable<Biome> context) {
SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder();

DefaultBiomeFeatures.addFarmAnimals(spawnSettings);
DefaultBiomeFeatures.addBatsAndMonsters(spawnSettings);
...
}

因为东西比较多,这里我们分开来看

首先创建一个SpawnSettings.Builder,这个是用于设置生物群系的生成设置

这里我们添加了一些原版的生物的生成

addFarmAnimals是添加可蓄养动物的生成,也就是牛、羊、猪这类

addBatsAndMonsters是添加蝙蝠和怪物的生成

1
2
3
4
5
6
7
8
9
10
11
12
private static Biome diamondBiome(Registerable<Biome> context) {
...
GenerationSettings.LookupBackedBuilder generationSettings =
new GenerationSettings.LookupBackedBuilder(context.getRegistryLookup(RegistryKeys.PLACED_FEATURE),
context.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER));

globalOverWorldGeneration(generationSettings);
DefaultBiomeFeatures.addMossyRocks(generationSettings);
DefaultBiomeFeatures.addDefaultOres(generationSettings);
DefaultBiomeFeatures.addExtraGoldOre(generationSettings);
...
}

这里写的是生物群系的一些地物的构造及放置特征,也有我们刚才写的那个方法,这里我们添加了一些原版的地物的构造

addMossyRocks是添加苔石的构造

addDefaultOres是添加默认矿石

addExtraGoldOre是添加额外的金矿石

1
2
3
4
5
6
7
private static Biome diamondBiome(Registerable<Biome> context) {
...
generationSettings.feature(GenerationStep.Feature.VEGETAL_DECORATION, VegetationPlacedFeatures.TREES_PLAINS);
DefaultBiomeFeatures.addForestFlowers(generationSettings);
DefaultBiomeFeatures.addLargeFerns(generationSettings);
...
}

然后是添加植被的构造,特征使用TREES_PLAINS,这个是原版的特征

addForestFlowers是添加繁花森林

addLargeFerns是添加大型蕨类植物

1
2
3
4
5
6
private static Biome diamondBiome(Registerable<Biome> context) {
...
DefaultBiomeFeatures.addDefaultMushrooms(generationSettings);
DefaultBiomeFeatures.addDefaultVegetation(generationSettings);
...
}

addDefaultMushrooms是添加默认的蘑菇

addDefaultVegetation是添加默认的植被

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static Biome diamondBiome(Registerable<Biome> context) {
...
return new Biome.Builder()
.precipitation(true)
.downfall(0.5f)
.temperature(0.7f)
.generationSettings(generationSettings.build())
.spawnSettings(spawnSettings.build())
.effects((new BiomeEffects.Builder())
.waterColor(0xe82e3b)
.waterFogColor(0xbf1b26)
.skyColor(0x78a7ff)
.grassColor(0x7c9b45)
.foliageColor(0x7c9b45)
.fogColor(0xc0d8ff)
.build())
.build();
}

那么最后一个就是这个生物群系的总体特征了,注册这个生物群系,这里我们设置了生物群系的一些特征

precipitation是降水,这里我们设置为true(有降水)

downfall是生物群系的降水量,这里我们设置为0.5f

temperature是生物群系的温度,这里我们设置为0.7f

spawnSettings是生物群系是生物生成设置,调用我们之前写的

generationSettings是生物群系构造的生成设置,同样也是我们之前写的

effects是生物群系的特效,确切来讲是一堆颜色,不设置的话它会根据前面的那些值自动设置。
waterColor是水的颜色,waterFogColor是水雾的颜色,skyColor是天空的颜色,grassColor是草方块的颜色,
foliageColor是叶子方块的颜色,fogColor是雾的颜色(因为是随机设置的,所以实际整个生物群系有点诡异)

另外,我也在这里说明一下,我这里写是写了一堆,但实际能否生成也得看这个生物群系的实际大小,有些特征可能会被覆盖

再一个,因为在后面的生物群系表面规则中,我们没有设置草方块,而是将原有的草方块代替成了钻石方块,所以这里的植被都不会生成(因为植被只能生成在土类方块上)

生物群系的生成会有很多因素制约它,区块的加载顺序也会影响到生物群系的生成,所以这里只是一个大概的设置

我这里罗列一堆只是教程演示,实际得根据你自己来

最后是用bootstrap方法注册生物群系

1
2
3
public static void bootstrap(Registerable<Biome> context) {
context.register(DIAMOND_BIOME, diamondBiome(context));
}

数据生成

那么同样的,先在数据生成类TutorialModDataGenerator中把这个bootstrap方法注册进去

1
registryBuilder.addRegistry(RegistryKeys.BIOME, ModBiomes::bootstrap);

以及在ModWorldGen进行注册

1
entries.addAll(wrapperLookup.getWrapperOrThrow(RegistryKeys.BIOME));

这样我们的生物群系就注册好了

ModOverworldRegion

我们接下来写ModOverworldRegion这个类,这个类用于将我们的生物群系注册添加到世界中,不过这里我们限定为主世界

1
2
3
4
5
public class ModOverWorldRegion extends Region {
public ModOverWorldRegion(Identifier name, int weight) {
super(name, RegionType.OVERWORLD, weight);
}
}

这个类继承Region(记得是TerraBlender的类),这里的构造方法我们也是要改写的,去掉原有的RegionType,直接写RegionType.OVERWORLD,这样就限定了这个生物群系只能在主世界生成

接下来我们重写addBiomes方法

1
2
3
4
5
6
@Override
public void addBiomes(Registry<Biome> registry, Consumer<com.mojang.datafixers.util.Pair<MultiNoiseUtil.NoiseHypercube, RegistryKey<Biome>>> mapper) {
this.addModifiedVanillaOverworldBiomes(mapper,modifiedVanillaOverworldBuilder -> {
modifiedVanillaOverworldBuilder.replaceBiome(BiomeKeys.FOREST,ModBiomes.DIAMOND_BIOME);
});
}

通过这个方法,我们可以将原版的生物群系替换成我们自己的生物群系,这里我们将原版的森林生物群系替换成我们的钻石大陆生物群系

ModMaterialRules

随后我们来写ModMaterialRules这个类,这个类用于指定生物群系表面的方块类型

首先指定一些材料规则

1
2
3
4
private static final MaterialRules.MaterialRule DIRT = makeStateRule(Blocks.DIRT);
private static final MaterialRules.MaterialRule GRASS_BLOCK = makeStateRule(Blocks.GRASS_BLOCK);
private static final MaterialRules.MaterialRule ICE_ETHER = makeStateRule(ModBlocks.ICE_ETHER_BLOCK);
private static final MaterialRules.MaterialRule DIAMOND = makeStateRule(Blocks.DIAMOND_BLOCK);

这里我们指定了一些方块的规则,这里我们指定了DIRTGRASS_BLOCKICE_ETHER_BLOCKDIAMOND

然后我们写makeRules方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static MaterialRules.MaterialRule makeRules() {
MaterialRules.MaterialCondition isAtOrAboveWaterLevel = MaterialRules.water(-1, 0);

MaterialRules.MaterialRule grassOnlyOnSurface = MaterialRules.condition(
MaterialRules.surface(),
MaterialRules.condition(isAtOrAboveWaterLevel, GRASS_BLOCK)
);

MaterialRules.MaterialRule diamondNearSurface = MaterialRules.condition(
MaterialRules.biome(ModBiomes.DIAMOND_BIOME),
MaterialRules.condition(MaterialRules.STONE_DEPTH_FLOOR_WITH_SURFACE_DEPTH, DIAMOND)
);

MaterialRules.MaterialRule dirtNearSurface = MaterialRules.condition(
MaterialRules.STONE_DEPTH_FLOOR_WITH_SURFACE_DEPTH,
DIRT
);

MaterialRules.MaterialRule iceEther = MaterialRules.condition(MaterialRules.STONE_DEPTH_CEILING, ICE_ETHER);

return MaterialRules.sequence(
grassOnlyOnSurface,
diamondNearSurface,
dirtNearSurface,
iceEther
);
}

这里我们写了一堆规则,这里我们指定了生物群系表面的方块类型

isAtOrAboveWaterLevel是指定在水面以上的方块

grassSurface是指定草地表面的方块

这里我们将世界表面的方块设置为GRASS_BLOCK,以供植被正常生成,水下表面和地下结构的表面用钻石块填充

当然,实际上要配置一个完整的生物群系仍需要很多规则,需要从基岩开始,到最顶端的空气,都需要配置

不过这里只做演示,大家可参考超多生物群系(BOP)

ModTerraBlenderAPI

那么最后就是ModTerraBlenderAPI这个类了,我们在onTerraBlenderInitialized方法中注册我们的生物群系和生物群系表面规则

1
2
3
4
5
@Override
public void onTerraBlenderInitialized() {
Regions.register(new ModOverWorldRegion(new Identifier(TutorialModRe.MOD_ID, "overworld"), 4));
SurfaceRuleManager.addSurfaceRules(SurfaceRuleManager.RuleCategory.OVERWORLD, TutorialModRe.MOD_ID, ModMaterialRules.makeRules());
}

通过Regions.register方法注册我们的生物群系,这里我们注册了位于主世界的生物群系,权重为4

然后通过SurfaceRuleManager.addSurfaceRules方法注册我们的生物群系表面规则,这里我们注册了我们的生物群系表面规则

在此之后,我们就可以跑数据生成了,生成我们的生物群系文件,之后就可以启动游戏

当然这里是得新建存档了,因为这个生物群系是新加入的