Tutorial: a custom dimension
This tutorial builds a dimension of floating islands, step by step. The finished project is examples/sky-islands, split into dimension.mms, terrain.mms and visit.mms. In the web editor, open it from Examples. The tests build it on every change, so it stays in step with the language.
A dimension is made of several resources that refer to each other by id:
| Resource | Kind | Says |
|---|---|---|
dimension_type |
DimensionType |
how the world behaves: height, light, sky |
worldgen/biome |
Biome |
climate, colours, mobs and features |
worldgen/noise and worldgen/density_function |
Noise, DensityFunction |
the terrain's shape |
worldgen/material_rule |
SurfaceRule |
which blocks cover the terrain |
worldgen/noise_settings |
NoiseSettings |
the generator: terrain, surface, sea level |
dimension |
Dimension |
the dimension itself, tying the rest together |
In MMS they can share one file or be split across several, since every file in the project sees every declaration. A name such as islands refers to the declaration of that kind in your namespace, and every reference is checked. Completion inside each { } lists the fields the game accepts.
1. Set up the project
mkdir sky-islands && cd sky-islands
mms init -namespace sky
This writes mms.json and a starter main.mms. You can put everything below in that file, or split it up the way the example does: the dimension type, biome and dimension in dimension.mms, steps 4 to 6 in terrain.mms, and the function in visit.mms. The order of files and declarations does not matter.
2. The dimension type
DimensionType islands {
height = 256
logical_height = 256
min_y = 0
coordinate_scale = 1
ambient_light = 0.1
has_skylight = true
has_ceiling = false
has_ender_dragon_fight = false
infiniburn = "#minecraft:infiniburn_overworld"
default_clock = overworld
monster_spawn_block_light_limit = 0
monster_spawn_light_level = 0
attributes = {
"minecraft:visual/sky_color" = "#9ad0ff"
"minecraft:visual/fog_color" = "#d8ecff"
"minecraft:visual/cloud_height" = 40
}
}
The world runs from y = 0 to y = 255. Low clouds at y = 40 drift below the islands. attributes holds environment attributes, the 26.3 home of sky, fog and music settings. Hover a field to read what it does.
3. A biome
Biome meadow {
temperature = 0.7
downfall = 0.6
has_precipitation = true
effects = { water_color = "#3f76e4" }
carvers = []
features = []
}
With no carvers and no features, the islands are bare stone, grass and dirt. To add trees or ores later, list placed features in features, one list per generation step.
4. The terrain
Terrain comes from a density function. Where it is above 0 the generator places default_block, and where it is below 0 it leaves air (or default_fluid below the sea level).
Noise island_noise {
base_octave = -6
amplitude_modifiers = [1, 1, 0.5]
}
Each entry in amplitude_modifiers is one octave. Minecraft also needs octave_count, which must match the length of the list. MMS fills it in for you when you leave it out, and reports an error if you set it to a different number.
// 0 at y = 128, rising to 1 at y = 32 and y = 224.
DensityFunction height = Gradient(
axis = y,
from_coordinate = 32,
to_coordinate = 224,
from_value = -1,
to_value = 1,
)
DensityFunction islands = Noise(island_noise, 1, 2) - height * height - 0.3
island_noiseis smooth 3D noise. A lowerbase_octavegives bigger shapes.heightis a gradient from -1 to 1 over the height of the world. Squared, it is 0 in the middle and 1 at the ends.islandssubtracts that from the noise. Solid blocks appear only where the noise is high and the height is near y = 128. Raising0.3makes the islands smaller and further apart.
The infix arithmetic compiles to sub and mul density functions. See Writing resources.
5. The surface
SurfaceRule surface = [
If(StoneDepth(Floor)) { Block(grass_block) },
If(StoneDepth(Floor).Offset(3)) { Block(dirt) },
]
The rules are tried in order. The top block of each floor becomes grass, and the three blocks below it become dirt. Everything else stays stone.
6. The generator settings
NoiseSettings islands {
sea_level = 0
default_block = stone
default_fluid = air
disable_mob_generation = false
legacy_random_source = false
noise = {
min_y = 0
height = 256
}
material_rule = surface
spawn_target = []
noise_router = {
final_density = islands
temperature = 0
vegetation = 0
continents = 0
erosion = 0
depth = 0
ridges = 0
chunk_surface_level = 0
}
}
noise must match the dimension type's min_y and height. The router's other entries drive biome placement and aquifers. With a single biome they can all be 0.
7. The dimension
Dimension islands {
type = islands
generator = {
type = noise
settings = islands
biome_source = {
type = fixed
biome = meadow
}
}
}
The names on the right are resolved by the field they are in: type names a DimensionType, settings names a NoiseSettings, and biome names a Biome. They all become sky:islands and sky:meadow in the JSON. If you mistype one, the editor reports it at once.
8. A way in
Function visit {
/execute in sky:islands run tp @s 0 160 0
tell(@s, "Welcome to the sky islands")
}
The command checker knows your project's dimensions, so in sky:islandz would be an error.
9. Build and play
mms build --world ~/.minecraft/saves/MyWorld
Custom dimensions load when a world starts, so restart the world, not just /reload, then run /function sky:visit.
Seeing worldgen changes
The game never generates a chunk twice: once you have visited a place, a change to the terrain only shows in chunks you have not been to yet. To look at the same place again with your changes, leave the world and build with --reset-dimensions:
mms build --world ~/.minecraft/saves/MyWorld --reset-dimensions
It deletes the saved chunks of each project dimension whose worldgen changed in this build, following ids: editing a noise that a density function in the dimension's noise settings uses counts, and so does a structure set that can place a structure in one of the dimension's biomes. The seed stays the same, so you see what your change did to the same terrain. The overworld, nether and end are never reset this way; name a dimension to reset it whatever changed, as in --reset-dimensions=sky:islands (or minecraft:the_nether, which deletes everything built there).
The old chunks move to the world's mms-reset folder, which keeps only the latest reset, so you can put them back. The build refuses to reset while Minecraft has the world open, because the game would save the chunks it has loaded again; save and quit to title first. If you logged out inside the dimension, you come back at the same place in fresh terrain, which may be inside a hill.
In VS Code, tick Reset changed dimensions under Build into world in the MMS side bar, or use Reset terrain… in a dimension's ⋯ menu.
Next steps
- Use a
multi_noisebiome source and the router'stemperatureandvegetationentries for several biomes. - Add features to the biome's
featureslists. - Turn on aquifers by adding an
aquifersblock to the settings. - Import a vanilla dimension with
mms importto see a complete one written in MMS.