===== Custom Chunk Generators ===== ''ChunkGenerator''s are the mechanisms by which the game generates the world. They handle terrain shaping, surface building, and biome placement. Vanilla Minecraft's ''NoiseChunkGenerator'' is extremely powerful and configurable. Using ''DensityFunction''s and ''SurfaceRule''s, the possibilities for customization are almost endless. **If you're wondering "can I do x with ''NoiseChunkGenerator'' and datapacks", the answer is probably yes.** Most situations do not call for a custom ''ChunkGenerator'', and since creating one requires a lot of boilerplate code, **it is highly recommended that you avoid making custom ''ChunkGenerator''s when possible.** As a rule of thumb, you should only implement a ''ChunkGenerator'' if you need to create a world that is **not** based on random noise. Examples of this might include a world generated from an external voxel engine, or a custom map like SethBling's Skygrid. If you're not sure whether a ''ChunkGenerator'' is right for you, ask someone in the Discord. Ready? Let's get started. ==== Creating a ChunkGenerator ==== The first step in creating a chunk generator is making a new ''ChunkGenerator'' class. Extend vanilla's ''ChunkGenerator'', and let your IDE generate all the required function stubs. Here's an explanation of everything you likely need to worry about: public class ExampleChunkGenerator extends ChunkGenerator { /* this is a very important field, we will come back to the codec later */ public static final Codec CODEC; /* you can add whatever fields you want to this constructor, as long as they're added to the codec as well */ public ExampleChunkGenerator() { } /* the method that creates non-noise caves (i.e., all the caves we had before the caves and cliffs update) */ @Override public void carve(ChunkRegion chunkRegion, long seed, NoiseConfig noiseConfig, BiomeAccess biomeAccess, StructureAccessor structureAccessor, Chunk chunk, GenerationStep.Carver carverStep) { } /* the method that places grass, dirt, and other things on top of the world, as well as handling the bedrock and deepslate layers, as well as a few other miscellaneous things. without this method, your world is just a blank stone (or whatever your default block is) canvas (plus any ores, etc) */ @Override public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) { } /* the method that paints biomes on top of the already-generated terrain. if you leave this method alone, the entire world will be a River biome. note that this does not mean that the world will all be water; but drowned and salmon will spawn. */ @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); } /* this method spawns entities in the world */ @Override public void populateEntities(ChunkRegion region) { } /* the distance between the highest and lowest points in the world. in vanilla, this is 384 (64+320) */ @Override public int getWorldHeight() { return 0; } /* this method builds the shape of the terrain. it places stone everywhere, which will later be overwritten with grass, terracotta, snow, sand, etc by the buildSurface method. it also is responsible for putting the water in oceans. it returns a CompletableFuture-- you'll likely want this to be delegated to worker threads. */ @Override public CompletableFuture populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig, StructureAccessor structureAccessor, Chunk chunk) { } @Override public int getSeaLevel() { return 0; } /* the lowest value that blocks can be placed in the world. in a vanilla world, this is -64. */ @Override public int getMinimumY() { return 0; } /* this method returns the height of the terrain at a given coordinate. it's used for structure generation */ @Override public int getHeight(int x, int z, Heightmap.Type heightmap, HeightLimitView world, NoiseConfig noiseConfig) { return 0; } /* this method returns a "core sample" of the world at a given coordinate. it's used for structure generation */ @Override public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView world, NoiseConfig noiseConfig) { } /* this method adds text to the f3 menu. for NoiseChunkGenerator, it's the NoiseRouter line */ @Override public void getDebugHudText(List text, NoiseConfig noiseConfig, BlockPos pos) { } @Override protected Codec getCodec() { return CODEC; } } Pretty much all of these methods need to be overridden for your generator to work properly. You can copy some of them from ''NoiseChunkGenerator''. It is especially recommended that you implement the private ''populateNoise'' method from ''NoiseChunkGenerator'' as well, and just copy over the public method. The public method from ''NoiseChunkGenerator'' just delegates the actual generation to worker threads, which each run the private method. This is an easy way to get parallelized generation-- **the chunk generator is not multithreaded by default**! ==== Registering and Codecs ==== Like other features in the game, ''ChunkGenerators'' have to be registered. However, you don't pass the registry a static instance-- instead, you give it a ''Codec'' instance. You can put whatever you want in the codec-- Mojang provides serialization codecs for a lot of useful objects, including entire registries. Then, all that's left is to register your chunk generator. Put the following line into your mod initializer ''onInitialize'' method: Registry.register(Registry.CHUNK_GENERATOR, new Identifier("wiki-example", "example"), ExampleChunkGenerator.CODEC); And you're done! If you want to use your new generator, it might be helpful to wrap it with a [[tutorial:world_presets|WorldPreset]].