Creating a new dimension using vanilla datapack functionality is easy! However, if your want finer control over your dimension, you'll need to implement it in code. Here's a few useful concepts for this process:
World class is the in-game representation of a world. It's what is mutated when you place or destroy blocks. It's not used during worldgen. Instead, a dimension is made of a few parts, as shown here:
DimensionType handles the overarching logic surrounding your dimension. Can a player sleep in a bed here? How high does the world extend? How dark does it need to be for mobs to spawn? Can the player see the sky? It's also responsible for saving and loading your dimension from a file.
A biome is a container for Features– things like structures, trees, flower patches, ores– and a set of monster spawn rules, as well as temperature and precipitation information. It also contains some clientside effects like the sky, water, and fog colors, particles, and ambient sounds.
Responsible for placing all the naturally-generated blocks in the world, as well as biome placement. In vanilla implementations, especially
NoiseChunkGenerator, biome placement is outsourced to a BiomeSource, (some) cave generation is outsourced to a Carver, and placement of “painted-on” blocks like grass, bedrock, and deepslate is outsourced to a SurfaceRule. These are elaborated on below, but are not strictly necessary for a dimension implementation:
BiomeSource places the biomes over the world. Note that according to
MultiNoiseBiomeSource, which is vanilla's implementation, where biomes are placed is independent of the terrain features at that point.
MultiNoiseBiomeSource makes sure that biomes spawn where they should by, for example, making the noise values that correspond to high terrain as dictated by the
NoiseChunkGenerator also correspond to mountain biomes. If you're confused, generate a world with the “Single Biome” preset and choose an ocean biome– the world will still have mountains and valleys and rivers, but everything will be an ocean biome.
Surface rules “paint” blocks like dirt and grass onto the world. I use the word “paint” because they don't actually generate any new blocks; they just modify that which is already there. The vanilla surface rule is basically a giant chained if statement:
if (desert) placeSand(); else if (plains) placeGrass(); et cetera.
Carvers are responsible for generating non-noise caves, or, more accurately, “carved caves”. The difference is nuanced, but as a rule of thumb, all pre-Caves and Cliffs caves are carved caves, and the cave types that were added in that update are so-called “noise caves.” Keep in mind that this name is a misnomer, as all caves are generated using noise.
The World Preset is the option the player is presented when starting a new world. It's mainly a wrapper for your ChunkGenerator. AMPLIFIED, Large Biomes, Default, and Superflat are examples of vanilla world presets.