3x Actions, 3x Skill Gains, Epic skill curve - Roleplay - PvPvE - Custom Map, Mods, Religions, Creatures etc. - Friendly Community

Kenabil's Map Generator

About the Map Generator

The map generator software is open source, and the project is hosted on Bitbucket:

https://bitbucket.org/spirangle-studio/wu-map-generator/

Download the latest version of the map generator software here:

https://awakening.spirangle.net/download/mapgen-1.0.0.zip

Wurm Online forum thread:

https://forum.wurmonline.com/index.php?/topic/165809-map-generator-flavor-alternative/

The map generator builds a Wurm Unlimited terrain. It does not build a server. The run writes five mesh files and a set of pictures under ./maps/<mapName>/, relative to the directory you started it from. Players, items, zones, and the rest of a world are not in those files.

The window title is Map Generator for Wurm Unlimited, version 1.0.0. The first argument is the properties name, without .properties. If you omit it, the name is mapgen, and the file read is mapgen.properties in the working directory. A missing file is logged and is not replaced by the defaults. A value that does not parse stops the load at that line.

Create ./maps/<mapName>/ before the first render. The heightmap picture is written before the world directory is created, and that write does not reliably create the folder.

Do not point it at a world you want to keep. The first time a view has to open the map, the five mesh files in that folder are deleted and created again. Quick Map does this as soon as it shows the terrain. Only Render Map writes the finished terrain back out.

Map size must be a power of two from 1024 to 32768. Those are the sizes the world files can be created at. Anything else will not match the grid being generated.

Two buttons

Nothing starts while the progress bar is short of 100.

Quick Map reloads the properties file, generates a new heightmap, overwrites heightmap.png, and drops two dirt passes. It does not import an existing heightmap. It does not erode, fracture, place ore, or run biomes. It does not save a playable map. It is a shape preview, and it will replace a heightmap you edited.

Render Map does not reload the properties. Restart after editing them, or run Quick Map once, which does reload, before Render Map. The full pass is:

  1. If ./maps/<mapName>/heightmap.png exists and is square and the right size, that picture is the terrain. Otherwise, the heightmap is generated and that picture is written.
  2. The rock is eroded, then fractured.
  3. Dirt is dropped, using dirtDropCount.
  4. Dirt is eroded.
  5. Ore is rolled.
  6. If biomemap.png is present, it is painted, and then biomes are generated.
  7. Pictures are written, and the mesh files are saved.

The heightmap picture is not rewritten after erosion. A second Render Map imports the same picture and erodes it again from that original. Delete heightmap.png when you want a new shape. Set erosionIterations to 0 and erosionFracture to 0 when you want the picture left alone. Those two settings are shared with the dirt pass, so this also skips dirt erosion. There is no separate switch.

Tree and bush ages are rolled from the clock at save time. They are not part of the seed. Two renders from the same properties will not have the same ages.

Seeds and the name

heightSeed 0 and an empty mapName take the seed from the clock and use that number as the name. The log prints it. Keep that number if you want the same terrain again.

heightSeed 0 and a name set the seed from the name's hash. The same name is the same seed, including a negative hash.

A non-zero heightSeed with an empty name uses the seed as the name.

normalizeSeed, fractureSeed, and biomeSeed of 0 copy the height seed. Set any of them to its own value to change only that pass. Ore and biomes both start from biomeSeed. The plant rolls and the ore rolls do not depend on each other.

Height

Every height setting is in the same unit. 0 is the bottom of the range, mapHeight is the top. The default range is 4096. The water line is waterHeight, default 500. In the mesh, that line is height 0. A tile below it is stored as a negative height, which is water. The marker's Height number is this same unit, so a shore tile reads about 500. The height stored in the file is that number minus waterHeight.

mapHeight is also the vertical scale written into the file. Extreme values are what the map code warns will crash a server. The default sits well inside a signed short.

The shape is simplex noise, heightMapIterations octaves, default 10. The first three octaves use mapResolution. The rest use landscapeResolution. A larger resolution is a longer wave and broader hills. A smaller one is choppier. The fallback for both, and for biomeResolution, is 256, which is the default map size divided by 8. Changing mapSize does not change that fallback. If you change the size and want the same kind of hills, set the resolutions yourself.

heightMapCompression, default 25, is applied after the octaves. The range is refit to its highest point, run through a curve that pushes the body of the land down, and the peaks are left standing. Higher compression does more of that. It is not a percentage of flatness.

moreLand, default true, keeps low noise and shifts it up, instead of cutting it off at zero on every octave. More of the range ends above the water line. Set it to false and lows are clipped on every pass. Only the string true is true.

On the last octave, and only when the heightmap is generated rather than imported, the outer heightMapMinEdge tiles are forced to zero. Default 64. Inside that, height is faded down across mapSize / heightMapBorderWeight tiles. Default weight 6, so on a 2048 map the fade is about 341 tiles. Normalization and erosion run after this and can lift the faded band. The hard empty strip is the outer minimum edge. An imported heightmap skips the fade entirely.

heightMapPeaks is not a count of mountains. It is only used by fracture. Strong fracture starts at height 1 - peaks/100. Default 20 means height 0.80 and above. Raising it brings that band down. It does not turn fracture off. erosionFracture 0 does.

What a 16-bit height picture contains

The exported heightmap.png is 16-bit grayscale, one pixel per tile, 0 low and 65535 high. That is the format to edit and put back. A color PNG can be read, but the height is taken from the packed bytes, so a round trip is the grayscale file. It must be square and exactly mapSize on a side, or it is refused and a new heightmap is generated instead.

Dirt

Dirt is not a heightmap. It is a count of passes over the rock.

On a slope, less dirt is accepted. The drop to the steepest neighbor is multiplied by cliffRatio, default 2.5, and compared with the average of maxDirtSlope and maxDirtDiagSlope. At the defaults that average is 60, so a neighbor drop of 24 or more accepts no dirt, a drop of 12 accepts half of dirtDropCount, and flat rock accepts all of it. That is why cliffs stay bare. cliffRatio does not change the rock.

Nothing is added once the combined height passes dirtHeight, default 3300. The last few passes also taper off just below that.

landSlide, default false, leaves the dirt on the tile that earned it. Set it to true and each bit walks downhill until no neighbor is lower by maxDirtSlope on a side, or maxDirtDiagSlope on a diagonal. The walk uses the biome seed. It can run a long way. Leave it off unless you want that.

The passes run at the same time, one thread per pass. The count on a tile is about dirtDropCount, not a guaranteed stack.

Where dirt does land, the type is taken from height:

Combined height Type
0 dirt Rock
Below the water line Dirt
Water line up to tundraHeight Grass
tundraHeight up to the packed line Tundra
Packed line up to snowHeight Packed dirt
snowHeight and above Snow

The packed line is not a setting. If snow is above tundra, it sits two-thirds of the way from tundra to snow. Defaults: water 500, tundra 3000, packed about 3594, snow 3900.

Dirt stops at 3300, which is below the snow line. Rock that already sits between 3300 and 3900 never receives dirt and stays rock. Snow above 3900 is applied afterwards, and a bare peak is given one dirt so the snow has something to sit on. Tundra is only where dirt actually climbed into that band. It is not a clean belt around the mountains.

On save, a tile whose rock is higher than its surface is raised to the rock, and a tile with no dirt on any corner is written as rock. A surface type with no dirt depth does not survive the save.

Erosion

erosionMinSlope and erosionMaxSlope are in the same height units. Default 30 and 300. On the rock pass, a neighbor drop inside that range moves material downhill. Gentler than 30 does not move. Steeper than 300 does not move, which is what leaves cliffs. erosionMaxSediment, default 100, scales how much moves per pass. erosionIterations, default 30, is how many passes.

The dirt pass uses the iteration count and ignores the slope and sediment settings. Any lower dirt neighbor can take dirt, including a drop of one unit, and the search may step across up to three rock tiles to find one. Snow and bare tiles are skipped. Raise the minimum slope to protect rock detail. It will not protect dirt detail.

Fracture runs after the rock erosion and before the dirt. erosionFracture, default 20, is the amount of random vertical noise, five times stronger inside the peaks band and half strength outside it. The map is refit to the range afterwards. 0 skips it.

Ore

Each ore value is a percentage of cave tiles, not a weight. The roll is 0 to 100, and the percentages are subtracted in this order: ordinary wall, iron, gold, silver, zinc, copper, lead, tin, adamantine, glimmersteel, marble, slate, sandstone, rock salt. Whatever is left is ordinary wall as well. Ordinary wall is not a setting. It is 100 minus the sum of the ore values. If the sum is over 100, ore generation stops and the log says the values are out of range.

Defaults sum to 2.7, so 97.3% of the cave is empty wall. Iron is 1%. Gold is 0.05%. Adamantine and glimmersteel are 0, and do not appear until you set them.

A wall tile is given 40 to 59 mining actions. Any vein or stone type is given 90 to 15089. The whole cave layer is solid. No tunnel, no entrance, and no open cavern is written. The cave picture is that solid layer.

Blue on the cave picture is rock below the water line. It is the same tint the surface pictures use. It does not mean the cave is flooded.

Color on the cave picture What was written
Dark gray Cave wall
Dark red Iron
Dark yellow Gold
Light gray Silver
Near white Zinc
Green Copper
Dark pink Lead
Gray Tin
Cyan Adamantine
Bright yellow Glimmersteel
White Marble
Black Slate
Dark orange Sandstone
Bright cyan Rock salt
Pink Open cave, or a type this generator does not write

Biomes

Biome noise uses biomeResolution, default 256, same rule as the height resolutions. Climate is the long wave. The environment value is a shorter wave. Both are centered on zero. The log prints the ranges from the last quarter of the map at the end of the pass.

Temperature is computed from position, distance from the center, those two waves, and height. High ground is pulled toward cold. The halfway lines of the map are generated as four quarters, so a seam in plant cover along the middle is expected. The outer two tiles keep whatever the dirt pass left there.

These four settings are read and do nothing. The code that would have used them is commented out:

Sand, steppe, tundra, snow, and packed dirt are not placed by those temperatures. Tundra, packed dirt, and snow come from the dirt pass, as above. Sand, steppe, clay, peat, and tar come from the rules below, on tiles the dirt pass left as grass, tree, or bush.

A tile is treated as land only when it and its east, south, and southeast neighbors are all on or above the water line. Otherwise the underwater rules apply.

biomeBeaches, default 50, is a threshold on the environment wave, not a width in tiles. 50 puts the threshold at 0. 0 makes it about −0.125. 100 makes it about 0.125. Higher means more sand.

biomeClayPits moves a different threshold a short distance. Default 50 is 0.10. The useful range of the setting is about 0.075 to 0.125. Higher means slightly more clay.

On land that is still grass, tree, or bush:

Slope here is the height difference to the neighboring corner, in the same units as waterHeight. It is not maxDirtSlope and not the erosion slope. A limit of 20 is flat ground. Peat, tar, and clay are flat pockets for that reason. Those cutoffs are not settings.

Underwater:

Marsh is not generated. It only appears if the paint file places it. A marsh tile turns nearby sand and dirt into clay.

A hole deeper than 10, surrounded by dirt, is filled to about 95% before the types are chosen.

The paint file

./maps/<mapName>/biomemap.png is read at the start of the biome pass, if it is there. It is not overwritten. The picture written at the end is biomes.png, which is a different palette. Do not feed biomes.png back in as the paint file. The view colors will not be recognized.

The paint file must be square, exactly mapSize, and 24-bit or 32-bit. Any other color is ignored. It only paints tiles the dirt pass left as grass, with one exception: marsh is also accepted on other types, and only if the tile is within 7 height units below the water line. Rock, snow, tundra, and packed dirt are not paintable. The grass band is the land between the water line and tundraHeight.

Color Type
#66FF66 Grass
#009900 Generic tree
#33FF33 Generic bush
#FFFF00 Sand
#00FF00 Steppe
#FFCC99 Dirt
#CC9966 Packed dirt
#999999 Clay
#663300 Peat
#333333 Tar
#99FF00 Moss
#00FF99 Marsh
#FF00FF Mycelium
#FFFFFF Snow
#CCCCCC Tundra
#FF9900 Lava

Above water, a painted type other than generic tree or generic bush is kept. Tree and bush pixels still go through the plant roll, and the land rules above can turn them into sand, clay, peat, tar, or moss first. Below water, the underwater rules can still replace what you painted. Lava is left alone. Mycelium is kept on land. It does not produce mycelium trees. Trees written by this generator are normal trees.

Without this file there are no generic tree or bush tiles. The dirt pass never makes them.

Plants

biomePlantDensity, default 40, is a percentage, and it does not mean the same thing on every tile.

On grass, only a twentieth of that percentage is planted. At 40, that is 2% of grass tiles. The other 98% stay grass. This is the only planting a render does if you did not paint tree or bush pixels.

On a painted generic tree or bush pixel, the full percentage becomes a specific species. At 40, 60% of those pixels are turned back into grass. Half a tenth of the percentage becomes a bush where a tree was painted, or a tree where a bush was painted. The rest of the percentage becomes the species matching what you painted.

biomeFlowerDensity, default 30, is the percentage of grass that still is grass which receives a flower, type 1 through 7, equal odds. Flowers are not placed on tiles that became a tree or a bush. Grass is written at medium growth.

Five percent of tundra becomes lingonberry. That roll is fixed. Density does not scale it.

Which species are allowed is the temperature band. These three settings are the ones that actually select plants. Defaults are subtropical 12, Mediterranean 8, temperate 5.

Cedar prefers a positive environment value. Pine and fir prefer a negative one. The roll inside a band is weighted, not even. Nothing in the cold band is oak, fruit, or grape. Nothing above the subtropical line is pine or fir.

Ages are every foliage age the game defines, including sprout and overaged, picked at save from the clock. The grass stage under a tree or bush is medium. No fruit bit is set.

When the mesh is written, each tile that is not rock, tree, or bush paints its type onto the eight tiles around it, and trees and bushes are written after that, on their own tile. A one-tile paint can be covered by a neighbor, and it also spills onto its neighbors. Leave a margin around a feature you care about.

The window

The bar has to be at 100 before a button does anything. The log is the right-hand pane. The memory line is the percent of the JVM's max heap in use. A large map needs a larger heap. The generator will not pick one for you.

The view buttons do not regenerate anything.

Drag pans. The wheel zooms toward the cursor. Shift zooms faster. Right-click toggles a marker. The label is tile, player, height. Player is the tile times 4, the in-game meter coordinate for that tile. Tile Y is measured from the bottom of the picture. Height is the generator unit, the same one as waterHeight.

Grid draws that many cells across the map. Default 8. It is a count, not a tile size. Enter commits the field. It has no effect on the map.

For a map of 32768, the topographic and cave pictures are a random 16384 window, not the whole map. The isometric dump is the whole map. At 16384 and below, the pictures are the whole map.

Files

File What it is
heightmap.png Input and output. 16-bit gray. Generated only when missing. Quick Map overwrites it.
biomemap.png Optional paint input. Not overwritten.
map.png Isometric dump.
topography.png Contours every 250, water shown.
cave.png Solid cave layer, water tint shown.
biomes.png View palette. Not a paint file.
top_layer.map Surface type and height.
rock_layer.map Rock height.
map_cave.map Solid cave wall and vein type.
resources.map Mining actions on that vein.
flags.map Created and not filled in.

saveChanges is the point at which the five mesh files hold the finished terrain. A render stopped after the first map view may already have wiped them.

Properties

Missing keys fall back to these. A bad value does not.

mapName=
mapSize=2048
mapHeight=4096
mapResolution=256
landscapeResolution=256

heightSeed=0
normalizeSeed=0
fractureSeed=0

heightMapIterations=10
heightMapMinEdge=64
heightMapBorderWeight=6
heightMapCompression=25
heightMapPeaks=20

erosionIterations=30
erosionMinSlope=30
erosionMaxSlope=300
erosionMaxSediment=100
erosionFracture=20

dirtDropCount=60
maxDirtSlope=50
maxDirtDiagSlope=70
waterHeight=500
cliffRatio=2.5
dirtHeight=3300
snowHeight=3900
tundraHeight=3000
moreLand=true
landSlide=false

biomeSeed=0
biomeResolution=256
biomeDesertTemp=19.0
biomeSteppeTemp=17.0
biomeTundraTemp=1.8
biomeGlacierTemp=-1.0
biomeSubtropicalTemp=12.0
biomeMediterranTemp=8.0
biomeTemperateTemp=5.0
biomePlantDensity=40
biomeFlowerDensity=30
biomeBeaches=50
biomeClayPits=50

oreIron=1.0
oreGold=0.05
oreSilver=0.1
oreZinc=0.15
oreCopper=0.2
oreLead=0.2
oreTin=0.2
oreAddy=0.0
oreGlimmer=0.0
oreMarble=0.2
oreSlate=0.2
oreSandstone=0.2
oreRocksalt=0.2

What it will not do

It will not reload properties for Render Map, and it will not leave an existing mesh file in that folder alone. It will not treat a color screenshot of the biome view as a paint file. It will not paint rock, snow, tundra, or packed dirt from biomemap.png.

It will not place desert, steppe, tundra, or snow from the four temperature settings that are currently unused. It will not grow a forest from biomePlantDensity alone. Without painted tree or bush pixels, that setting plants about a twentieth of itself on grass, and the rest of the grass gets flowers only.

It will not dig a cave, write an entrance, or leave an open cavern. It will not write a deed, a kingdom flag, an item, or a player. It will not reproduce tree ages from the seed. It will not skip rock erosion and still erode dirt. It will not honor the erosion slope settings on dirt.

It will not keep a one-tile painted feature from being covered by the neighbor smear on save, and it will not keep a surface type that has no dirt under it.