Table of Contents

自定义区块生成器

区块生成器 是游戏生成世界的机制。它们处理地形塑造,表面构建以及生物群落的放置。

原版我的世界的 噪声区块生成器 非常强大并且可配置。使用好 DensityFunction 以及 SurfaceRule ,自定义的可能性几乎是无穷无尽的。 如果你正在想 “我可以用 噪声区块生成器 和数据包做到某件事吗?”,那么答案往往为是。 大多数情况下不要自定义一个 区块生成器,并且由于重建一个需要大量的样板代码, 如果可能的话强烈建议你避免创建一个自定义的 区块生成器

根据经验,只有当您需要创建一个 不是 基于随机噪声的世界时,才应该实现 “区块生成器”。这方面的例子可能包括由外部体素引擎生成的世界,或像SethBling的Skygrid这样的自定义地图。如果你不确定 区块生成器 是否适合你,请询问Discord中的某人。

准备好了吗?让我们开始吧。

创建一个区块生成器

创建区块生成器的第一步是创建一个新的 ChunkGenerator 类。扩展原版的 ChunkGenerator,让IDE生成所有必需的函数模板。以下是您可能需要担心的所有问题的解释:

public class ExampleChunkGenerator extends ChunkGenerator {
    /* 这是一个非常重要的字段,我们稍后会回到这个编码器 */
    public static final Codec<ExampleChunkGenerator> 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<Chunk> populateBiomes(Registry<Biome> 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<Chunk> 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<String> 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);

然后就完成了!如果你想用你的新生成器,用一个世界预设包装一下可能会很有帮助。