===== 自定义区块生成器 =====
''区块生成器'' 是游戏生成世界的机制。它们处理地形塑造,表面构建以及生物群落的放置。
原版我的世界的 ''噪声区块生成器'' 非常强大并且可配置。使用好 ''DensityFunction'' 以及 ''SurfaceRule'' ,自定义的可能性几乎是无穷无尽的。 **如果你正在想 “我可以用 ''噪声区块生成器'' 和数据包做到某件事吗?”,那么答案往往为是。** 大多数情况下不要自定义一个 ''区块生成器'',并且由于重建一个需要大量的样板代码, **如果可能的话强烈建议你避免创建一个自定义的 ''区块生成器''。**
根据经验,只有当您需要创建一个 **不是** 基于随机噪声的世界时,才应该实现 "区块生成器"。这方面的例子可能包括由外部体素引擎生成的世界,或像SethBling的Skygrid这样的自定义地图。如果你不确定 ''区块生成器'' 是否适合你,请询问Discord中的某人。
准备好了吗?让我们开始吧。
==== 创建一个区块生成器 ====
创建区块生成器的第一步是创建一个新的 ''ChunkGenerator'' 类。扩展原版的 ''ChunkGenerator'',让IDE生成所有必需的函数模板。以下是您可能需要担心的所有问题的解释:
public class ExampleChunkGenerator extends ChunkGenerator {
/* 这是一个非常重要的字段,我们稍后会回到这个编码器 */
public static final Codec CODEC;
/* 你可以在这个构造函数中添加任何你想要的字段,只要它们也被添加到了编码器中 */
public ExampleChunkGenerator() {
}
/* 这个方法创建非噪声生成洞穴(即我们在洞穴与山崖更新之前拥有的所有洞穴) */
@Override
public void carve(ChunkRegion chunkRegion, long seed, NoiseConfig noiseConfig, BiomeAccess biomeAccess, StructureAccessor structureAccessor, Chunk chunk, GenerationStep.Carver carverStep) {
}
/* 这个方法在世界顶部放置草,泥土和其他的东西,还处理基岩和深板岩层,以及一些其他杂项内容。没有这个方法,你的世界就只是一个空白的石头(或者是你的默认方块)画布(加上矿石等东西 */
@Override
public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) {
}
/* 这个方法在已经生成的地形上绘制生物群系。如果你不修改这个方法,整个世界将会全是河流群系,
注意这并不意味着整个世界都是水;但是淹死的生物和鲑鱼会生成。 */
@Override
public CompletableFuture populateBiomes(Registry biomeRegistry, Executor executor, NoiseConfig noiseConfig, Blender blender, StructureAccessor structureAccessor, Chunk chunk) {
return super.populateBiomes(biomeRegistry, executor, noiseConfig, blender, structureAccessor, chunk);
}
/* 这个方法在世界中生成实体 */
@Override
public void populateEntities(ChunkRegion region) {
}
/* 世界中最高点和最低点之间的距离。在原版中,这个值是384(64+320) */
@Override
public int getWorldHeight() {
return 0;
}
/* 这个方法构建地形的形状。它到处放置石头,这些石头后来会被 buildSurface 方法覆盖成草、陶土、雪、沙子等。它还负责将水放入海洋中。它返回一个 CompletableFuture -- 你可能希望将其委托给工作线程。 */
@Override
public CompletableFuture populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig, StructureAccessor structureAccessor, Chunk chunk) {
}
@Override
public int getSeaLevel() {
return 0;
}
/* 世界中可以放置方块的最低值。在原版世界中,这个值是-64 */
@Override
public int getMinimumY() {
return 0;
}
/* 这个方法返回给定坐标的地形高度。它用于结构生成 */
@Override
public int getHeight(int x, int z, Heightmap.Type heightmap, HeightLimitView world, NoiseConfig noiseConfig) {
return 0;
}
/* 这个方法返回给定坐标的世界“核心样本”。它用于结构生成 */
@Override
public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView world, NoiseConfig noiseConfig) {
}
/* 这个方法向 f3 菜单添加文本。对于 NoiseChunkGenerator,它是 NoiseRouter 行 */
@Override
public void getDebugHudText(List text, NoiseConfig noiseConfig, BlockPos pos) {
}
@Override
protected Codec extends ChunkGenerator> getCodec() {
return CODEC;
}
}
几乎所有这些方法都需要重写,生成器才能正常工作。您可以从 ''NoiseChunkGenerator'' 中复制其中一些。特别建议您也从 ''NoiseChunkGenerator'' 中实现私有的 ''populationNoise'' 方法,只需复制公共方法即可。''NoiseChunkGenerator'' 中的公共方法只是将实际生成委派给工作线程,每个工作线程都运行专用方法。这是一种获得并行生成的简单方法—— **区块生成器默认情况下不是多线程的**!
==== 注册和编码器 ====
与游戏中的其他功能一样,''ChunkGenerators'' 也必须注册。但是,您不向注册表传递静态实例,而是给它一个 ''Codec'' 实例。您可以在编码器中放入您想要的任何内容—— Mojang 为许多有用的对象(包括整个注册表)提供序列化编码器。然后,剩下的就是注册区块生成器。将以下代码放入您的模组 initializer 中的 ''onInitialize'' 方法中:
Registry.register(Registry.CHUNK_GENERATOR, new Identifier("wiki-example", "example"), ExampleChunkGenerator.CODEC);
然后就完成了!如果你想用你的新生成器,用一个[[zh_cn:tutorial:world_presets|世界预设]]包装一下可能会很有帮助。