本篇教程的视频

(待发布)

本篇教程的源代码

(待发布)

本篇教程目标

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

准备工作

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

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

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

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

1
2
3
4
5
6
7
8
9
10
buildscript {
repositories {
maven {
url = 'https://maven.minecraftforge.net/'
}
maven {
url = 'https://repo.spongepowered.org/repository/maven-public/'
}
}
}

当然这里我们需要额外引入一个Mixin的依赖,因为TerraBlender需要Mixin环境,但Forge本身没有

还需要一个插件

1
2
3
plugins {
id 'org.spongepowered.mixin' version '0.7.+'
}

然后是TerraBlender依赖和版本

1
2
3
dependencies {
implementation fg.deobf('com.github.glitchfiend:TerraBlender-forge:1.20.1-3.0.1.10')
}

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

然后重载Gradle,让它下载依赖

创建一堆类

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

创建ModBiomes类

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

1
2
3
public class ModBiomes {

}

创建ModOverworldRegion类

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

1
2
3
public class ModOverworldRegion {

}

创建ModTerraBlenderAPI类

这个类用于TerraBlenderAPI的使用

1
2
3
public class ModTerraBlenderAPI {

}

创建ModSurfaceRules类

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

1
2
3
public class ModSurfaceRules {

}

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

注册群系

ModBiomes

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

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

1
2
public static final ResourceKey<Biome> DIAMOND_BIOME = ResourceKey.create(Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, "diamond_biome"));

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

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

1
2
3
4
5
6
7
8
public static void globalOverWorldGeneration(BiomeGenerationSettings.Builder builder) {
BiomeDefaultFeatures.addDefaultCarversAndLakes(builder);
BiomeDefaultFeatures.addDefaultCrystalFormations(builder);
BiomeDefaultFeatures.addDefaultMonsterRoom(builder);
BiomeDefaultFeatures.addDefaultUndergroundVariety(builder);
BiomeDefaultFeatures.addDefaultSprings(builder);
BiomeDefaultFeatures.addSurfaceFreezing(builder);
}

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

addDefaultCarversAndLakes是添加洞穴、湖泊构造

addDefaultCrystalFormations是添加紫水晶洞穴的构造

addDefaultMonsterRoom是添加地牢的构造

addDefaultUndergroundVariety是添加矿物的构造

addDefaultSprings是添加地下河的构造

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

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

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

BiomeDefaultFeatures.farmAnimals(spawnSettings);
BiomeDefaultFeatures.commonSpawns(spawnSettings);

...
}

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

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

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

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

commonSpawns是添加常规的怪物生成

1
2
3
4
5
6
7
8
9
10
11
12
private static Biome diamondBiome(BootstapContext<Biome> context) {
...
BiomeGenerationSettings.Builder generationSettings =
new BiomeGenerationSettings.Builder(context.lookup(Registries.PLACED_FEATURE),
context.lookup(Registries.CONFIGURED_CARVER));

globalOverWorldGeneration(generationSettings);
BiomeDefaultFeatures.addMossyStoneBlock(generationSettings);
BiomeDefaultFeatures.addDefaultOres(generationSettings);
BiomeDefaultFeatures.addExtraGold(generationSettings);
...
}

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

addMossyStoneBlock是添加苔石的构造

addDefaultOres是添加默认矿石

addExtraGold是添加额外的金矿石

1
2
3
4
5
6
7
private static Biome diamondBiome(BootstapContext<Biome> context) {
...
generationSettings.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, VegetationPlacements.TREES_PLAINS);
BiomeDefaultFeatures.addForestFlowers(generationSettings);
BiomeDefaultFeatures.addDefaultExtraVegetation(generationSettings);
...
}

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

addForestFlowers是添加繁花森林

addDefaultExtraVegetation是添加额外的植物,比如甘蔗、南瓜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static Biome diamondBiome(BootstapContext<Biome> context) {
...
return new Biome.BiomeBuilder()
.hasPrecipitation(true)
.downfall(0.5f)
.temperature(0.7f)
.generationSettings(generationSettings.build())
.mobSpawnSettings(spawnSettings.build())
.specialEffects((new BiomeSpecialEffects.Builder())
.waterColor(0xe82e3b)
.waterFogColor(0xbf1b26)
.skyColor(0x78a7ff)
.grassColorOverride(0x7c9b45)
.foliageColorOverride(0x7c9b45)
.fogColor(0xc0d8ff)
.build())
.build();
}

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

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

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

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

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

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

specialEffects是生物群系的特效,确切来讲是一堆颜色,不设置的话它会根据前面的那些值自动设置

  • waterColor是水的颜色
  • waterFogColor是水雾的颜色
  • skyColor是天空的颜色
  • grassColorOverride是草方块的颜色
  • foliageColorOverride是叶子方块的颜色
  • fogColor是雾的颜色

因为是随机设置的,所以实际整个生物群系有点诡异

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

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

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

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

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

数据生成

那么同样的,先在数据生成类ModWorldGenProvider中把这个bootstrap方法加到BUILDER

1
2
3
4
5
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)
.add(Registries.BIOME, ModBiomes::bootstrap);

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

ModOverworldRegion

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

1
2
3
4
5
public class ModOverworldRegion extends Region {
public ModOverworldRegion(ResourceLocation name, RegionType type, int weight) {
super(name, type, weight);
}
}

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

1
2
3
public ModOverworldRegion(ResourceLocation name, int weight) {
super(name, RegionType.OVERWORLD, weight);
}

接下来我们重写addBiomes方法

1
2
3
4
5
6
@Override
public void addBiomes(Registry<Biome> registry, Consumer<Pair<Climate.ParameterPoint, ResourceKey<Biome>>> mapper) {
this.addModifiedVanillaOverworldBiomes(mapper,modifiedVanillaOverworldBuilder -> {
modifiedVanillaOverworldBuilder.replaceBiome(Biomes.FOREST, ModBiomes.DIAMOND_BIOME);
});
}

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

ModTerraBlenderAPI

然后我们回到ModTerraBlenderAPI这个类,在里面写一个注册方法

1
2
3
4
public static void registerRegions() {
Regions.register(new ModOverworldRegion(
ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, "overworld"), 5));
}

我们还要在主类调用这个方法

1
ModTerraBlenderAPI.registerRegions();

ModSurfaceRules

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

首先指定一些材料规则

1
2
3
4
5
6
7
8
private static final SurfaceRules.RuleSource DIRT = makeStateRule(Blocks.DIRT);
private static final SurfaceRules.RuleSource GRASS_BLOCK = makeStateRule(Blocks.GRASS_BLOCK);
private static final SurfaceRules.RuleSource ICE_ETHER = makeStateRule(ModBlocks.ICE_ETHER_BLOCK.get());
private static final SurfaceRules.RuleSource DIAMOND = makeStateRule(Blocks.DIAMOND_BLOCK);

private static SurfaceRules.RuleSource makeStateRule(Block block) {
return SurfaceRules.state(block.defaultBlockState());
}

这里我们指定了一些方块的规则,这里我们指定了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 SurfaceRules.RuleSource makeRules() {
SurfaceRules.ConditionSource isAtOrAboveWaterLevel = SurfaceRules.waterBlockCheck(-1, 0);

SurfaceRules.RuleSource grassOnlyOnSurface = SurfaceRules.ifTrue(
SurfaceRules.abovePreliminarySurface(),
SurfaceRules.ifTrue(isAtOrAboveWaterLevel, GRASS_BLOCK)
);

SurfaceRules.RuleSource diamondNearSurface = SurfaceRules.ifTrue(
SurfaceRules.isBiome(ModBiomes.DIAMOND_BIOME),
SurfaceRules.ifTrue(SurfaceRules.DEEP_UNDER_FLOOR, DIAMOND)
);

SurfaceRules.RuleSource dirtNearSurface = SurfaceRules.ifTrue(
SurfaceRules.DEEP_UNDER_FLOOR,
DIRT
);

SurfaceRules.RuleSource iceEther = SurfaceRules.ifTrue(SurfaceRules.UNDER_CEILING, ICE_ETHER);

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

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

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

grassOnlyOnSurface是指定草地表面的方块

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

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

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

最后我们还要到模组主类的commonSetup方法中调用

1
SurfaceRuleManager.addSurfaceRules(SurfaceRuleManager.RuleCategory.OVERWORLD, MOD_ID, ModSurfaceRules.makeRules());

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

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