区块生成器
是游戏生成世界的机制。它们处理地形塑造,表面构建以及生物群落的放置。
原版我的世界的 噪声区块生成器
非常强大并且可配置。使用好 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);
然后就完成了!如果你想用你的新生成器,用一个世界预设包装一下可能会很有帮助。