This is a spinoff of McJty's youtube tutorials. The purposes of this project is to elaborate the dimension-creation code and subsequent worldgen. I will put up notes and sample code here as I can, partly for my own edification.
See the McJty tutorials and code at:
https://github.com/McJty/YouTubeModding14
This is a continuation/spinoff of McJty's tutorials. It assumes you have completed those tutorials, so start there.
Other skills you should need:
- Learning the basics of JSON
- learning how to read
run/logs/latest.log - Refreshing/rebuilding projects
gradlew --refresh-dependencies,gradlew --stop
I have almost zero experience modding minecraft. If you have questions, there are two discords that have experienced users: Modded Minecraft, and Minecraft Modded Development. A search for these discords will help you.
I'm working with ~1.17.1, keeping up to date as much as I can. With the release of 1.16.2, mojang started JSON-driven worldgen.
Resources to help with this JSON-driven worldgen are below.
Forge, the leading framework(?) for modding minecraft:
https://files.minecraftforge.net/net/minecraftforge/forge/
Forge documentation, such as registries
https://mcforge.readthedocs.io/en/latest/concepts/registries/
Wiki on creating dimension json files:
https://minecraft.gamepedia.com/Custom_dimension
Wiki on creating biome json files:
https://minecraft.fandom.com/wiki/Biome/JSON_format
Wiki on all other worldgen json files:
https://minecraft.fandom.com/wiki/Custom_world_generation
Structure tutorial github, with commented code and notes! https://github.com/TelepathicGrunt/StructureTutorialMod
Awesome tool to make creating worldgen json files much easier! Check it out!
https://misode.github.io/
Here's a datapack of the entire vanilla worldgen as a json datapack. This was created by mojang for 1.16.2+ as a great working example of the json worldgen system
https://cdn.discordapp.com/attachments/750505199415590942/779200847212576798/vanilla_wordgen.zip
As said, this is to elaborate on McJty's dimension code to build out a proper world generation mod.
To start off, this will focus on the minimal and simplest code necessary in Tutorial Dimension 1, which will use the JSON worldgen definitions.
There is too much in worldgen for me to directly break it down at once. I start with doing initial setup using the basics of JSON driven worldgen and elaborate over the steps.
The path and naming of your custom JSON files matter. The folder path will begin like resources.data.<modid>, followed by the folders for that particular JSON resource.
McJty's code includes Key Registry for the tutorial dimension, but this is only used for the custom Tp command he provides. We've commented out the teleport code as well as the Key Registry for the dim (and did some renaming for it and the dimension type).
The dimension code is located in:
In this case we use a JSON value of generator.biome_source.type = "minecraft:checkerboard" to make it easy to fly around in creative and glance at everything.
And technically we are done! Yes, just adding the JSON
For a first test, feel free to edit the tutdim1.json JSON to include other minecraft standard biome types. The Biome list is inside the JSON object at generator.biome_source.biomes
You should see this naming convention a lot in modding minecraft: "<modid>:name"
Ex: "minecraft:dark_forest", "minecraft:badlands", etc
Try adding your own "minecraft:" biomes from the complete list
With just a couple of minecraft biomes, two simple JSON files, code from ModDimensions (and code elsewhere in setup to include ModDomensions), you are finished specifying the basics of a new multi-biome dimension.
Visit it with:
/execute in yourmodid:dimension_id run tp @a ~ ~ ~
If you are confused at how to include the custom biomes, dimension types, and so on, take a look at tutdim1b.json.
Here we set a custom dimension type.
I strongly suggest using the wikis provided in Resources to familiarize yourself with the content to get an idea of what appears in Dimension Type.
In short, the dimension JSON data references are:
.type- theworldgen/dimension_typedata.generator.settings- theworldgen/noise_settingsdata.generator.type-.generator.biome_source.type-
Biome JSON can be set up without any loading code. The most basic sample biome is the tut1b_biome1_mcdef_red.json, found here:
You can add it to the biomes in tutdim1.json. It does not define any unique features, but creates a grim red biome that you should be able to fly to.
Try visiting your new dimension and flying around to find it.
With this you've added a new unique biome to your dimension!
Biome spawning behavior does not use a separate JSON file. Their data is found in the JSON biome at .spawners, and has six arrays: monster, creature, ambient, water_creature, water_ambient, misc.
An example of what might be contained in your .spawner.monster JSON block could look like this.
[
{
"type": "minecraft:spider",
"weight": 100,
"minCount": 4,
"maxCount": 4
},
{
"type": "minecraft:zombie",
"weight": 95,
"minCount": 4,
"maxCount": 4
}
]
The provided data pack in resources can be helpful here if you want to mimic minecraft spawn distribution.
The .spawn_costs JSON data isn't actually set in the default files, so I am leaving this blank (feel free to research it youself!).
Carvers have incredibly simple JSON files, like the example here (within path resources.data.fdztutorialmod.worldgen.configured_carver).
There are only six in default Minecraft (as seen in the downloadable resource). If you create a custom-carver or wish to change the ones in the biome, they are in the JSON at .carvers and cover two types: air and liquid.
You can see an example of this at the bottom of the tut1b_biome1_mcdef_red.json file ( in resources.data.fdztutorialmod.worldgen.biome).
Carvers often create features that cross biome borders, so it is useful to have the same carvers for biomes in the same dimension.
"minecraft:cave" and "minecraft:canyon" are found in nearly overworld biomes for its air carvers. However, the ocean biomes use "minecraft:ocean_cave" instead for its air-cave carver, and it uses liquid carvers:
- "minecraft:underwater_canyon"
- "minecraft:underwater_cave"
You can add a canyon carver to tut1b_biome1_mcdef_red.json, or make a custom carver with a high occurrence rate, and then run this to see all the canyons you'll get.
Carver JSON specification is extremely simple. A type specification invokes the name of the CarverBiome code being used. Probability gives the odds it will be used within the chunk.
Once again, building custom JSON is easily done using this resource: https://misode.github.io/worldgen/carver/
Custom carver code is complex, and is best addressed in other tutorials.
The .surface_builder value in the Biome JSON usually is a single string, naming a desired default or custom worldgen.configured_surface_builder resource.
You can also embed a custom configured surface builder as well, and an example of this is in
tut1b_biome1_mcdef_cyan.json(atresources.data.fdztutorialmod.worldgen.biome)
There are many surface builders in default Minecraft, usually paired with a related biome. There are some example surface builder JSONs at:
resources.data.fdztutorialmod.worldgen.configured_surface_builder
In the three examples, the primary notable trait is the .type value. This references what Surface Builder is called from the code. One pulls the default Surface Builder, the others pull custom ones set up for the Tutorial Dimension 1.
What's the difference between a Surface Builder and a Configured Surface Builder?
Configured Surface Builders define the blocks that the Surface Builder will actually use. The JSON file defines which Surface Builder (in code) will actually use it.
Biome JSON files then, call the Configured Surface Builder JSON name they want to use, and that one will name which Surface Builder it wants.
A feature object in the configured_feature JSON files have a type and a config. The type is the feature, and the config is how to configure that feature. It takes a decorator and a feature.
All "minecraft:decorated" does is take a decorator by config and then run that decorator to get a new position. It then feeds that new position to the feature.
With the haystack example, you end up with a series of decorators to establish the position you want to place at, and then you provide a feature to put there.
So creating custom features is a little more complicated. In this example, we implement the 'pile_hay' that's connected to the village structure spawning and instead have it generate in the world.
Below is a link to the feature, and an image of how it would appear in the Feature Generator.
data.fdztutorialmod.worldgen.configured_feature.fdz_testing_haystack.json
The count is the outermost Decorator and picks how many positions to attempt in the chunk. (You can play with the Feature Generator to see the various types of count decorators).
The square Decorator then randomizes the positions to an x/z spot in the chunk.
The heightmap snaps all the positions to the terrain.
And lastly, the "minecraft:pile_hay" is a reference to the Configured Feature to actually place at that position.
Thus, this Configured Feature sets up the position for the spawning of another Configured Feature.
You can read more about the config properties here:
https://minecraft.fandom.com/wiki/Configured_feature
block_pile- takes a block state provider to place one (or more) blocks.decorated- nestable feature, can use string references as well.delta_feature-disk- if there is water at the current block, place blocks in circular fomration based on input.fill_layer- fills all air blocks in a 16x1x16 layer, given a block state provider and an int height.fossil- places small structure, based on fossil/overlay structures and processors.freeze_top_layer- places snow, replaces water with ice, in snowy biomes. should be present in all biomes.geode.growing_plant-lake-netherrack_replace_blobs- replace all target blocks in certain radius (0-12) with another.ore- places ore/blocks of your choice, including a rules test and discard_chance_on_air_exposure.random_boolean_selector- randomly chooses between two equally likely features.random_patch- place plants/blocks based on tries, provided spread, and white/blacklist of replaceable blocks. Also takes a block_placer.
block_placer-simple_block_placer,double_plant_placer, or lastlycolumn_placerwith a min and extra size.
random_selector- randomly chooses a feature from a list with float chance. Places a default if none trigger.replace_single_block- replaces single block using list of targets/states.root_system- generates a root column of some blocks, w/ feature on top.simple_block- takes a block, and lists of valid blocks beneath the target, valid blocks at target, valid blocks above it.simple_random_selector- randomly chooses from a list of features, equally weighted.tree- creates a tree based on multiple properties.vegetation_patch- creates a patch of vegetation on a floor or ceiling. can take a depth, a range, radii, chance of generation, etc.
As per: https://minecraft.fandom.com/wiki/Configured_feature
I've left out a few enteries depending on how unusual or specific they are. These should help outline the main usable options and what they do.
Providers and Values
int providerconstant- straight in valueuniformorbiased_to_bottom- returns a number between two provided bounds. If the latter, will be biased to bottomclamped- clamps a value from another int provider between two provided bounds
vertical anchorabsolute- absolute height as seen in F3.above_bottom- relative height from bottom of the worldbelow top- relative height from top of the world
height providerconstant- vertical anchor to use as minimum heightuniform- returns a height between two vertical anchors.biased_to_bottomorvery_biased_to_bottom- asuniform, with biases. Has optionalinnervalue of minimum '1'.trapezoid- asuniform. Has optionalplateauvalue, a vertical anchor to use as the range in the middle of the trapezoid distribution (of uniform distribution). Defaults to 0.
heightmapvaluesMOTION_BLOCKING-MOTION_BLOCKING_NO_LEAVES-OCEAN_FLOOR-OCEAN_FLOOR_WG-WORLD_SURFACE-WORLD_SURFACE_WG-
block_state_providersimple_state_providerorrotated_block_provider- sets a block, and possible block properties.weighted_state_provider- one or more entries of blocks, each with an integeter weight and possible block properties.
Decorator Types
carving mask- returns list of all block positions in current chunk that have been carved out by a carver (not including noise caves). Takes eitherairorliquidas the carver type.cave_surface- modifies Y coord. Looks for a Y coord, either a floor or ceiling (depending on config), within an int provider search range. returns nothing if nothing is found.chance- returns current position or nothing (on failure). determined by 1/number.count- Returns multiple copies of the current block position. The count is determined by an int providercount_extra- Ascount, but number is determined by a base count and a chance to add an extra count. They are all plain ints.count_multilayer- Returns multiple block positions, placed on different vertical layers and spread in the X and Z direction with a range of 16. The count is per layer and determined by an int provider.count_noise- Ascount, but the number is either below_noise or above_noise, based on a noise value at the current block position. This noise is the same for each biome or dimension, only dependent on the X and Z coordinates. The count is calculated by noise(x / 200, z / 200) < noise_level ? below_noise : above_noise.count_noise_biased- Similar tocount_noise, the count is based on a noise value at the current block position, but instead of being only two possible values it can gradually change based on the noise value. The count is calculated by ceil((noise(x / noise_factor, z / noise_factor) + noise_offset) * noise_to_count_ratio).decorated- chains two decorators from this list. First runsouterdecorator, then loops the list of results throughinnerdecorator and combines the result.heightmap- modifies Y coord, set to the heightmap (if bottom of the world, returns nothing).heightmap_spread_double- modifies Y coord, set to a random value between bottom of world and double the heightmap.range- modifies Y coord, determined by height provider.spread_32_above- returns block position with modified Y coord, somewhere between +0 and +32 (excluded).square- returns block position with modified XZ coords, somewhere between +0 and +16 (excluded). ie- scatters the position across the chunk.water_depth_threshold- returns block position or nothing at all. Takes a height provider used to set new Y coord.
Biome JSON files have a lot more elements than dimensions. The wiki and github tool in Resources should make it much easier to understand the individual biome elements. But there are still two
. . . . (more to come here) . . . .
Biome JSONs define features in an "array of arrays", allowing each list to be executed in distinct steps. Minecraft organizes features this way into ten arrays held by features.
The below reference list is taken from Minecraft Overworld Biomes, and should give you an idea of what features are typically generated in each 'phase'.
If you are curious, they are named in net.minecraft.world.gen.GenerationStage.
The full, phase-sorted, lists of featuregen elements are here!
- RAW_GENERATION
- LAKES
minecraft:lake_water
minecraft:lake_lava
- LOCAL_MODIFICATIONS
(Rock Protrusions and Pillars)
minecraft:forest_rock
minecraft:iceberg_packed
- UNDERGROUND_STRUCTURES
(Fossils and 'Monster Rooms')
minecraft:monster_room
- SURFACE_STRUCTURES
minecraft:blue_ice
large_basalt_columns
- STRONGHOLDS
- UNDERGROUND_ORES
(including patches of dirt, clay, etc)
minecraft:ore_dirt
minecraft:ore_andesite
minecraft:ore_iron
minecraft:disk_sand
- UNDERGROUND_DECORATION
(and Nether Ore Gen - glowstone, quartz, soul fire flames)
minecraft:glowstone
minecraft:ore_quartz_nether
- VEGETAL_DECORATION
(Vegetation Patches, Water/Lava Springs)
minecraft:plain_vegetation
minecraft:patch_sugar_cane
minecraft:spring_lava
- TOP_LAYER_MODIFICATION
(void start platform, top layer freeze?)
minecraft:freeze_top_layer
...