Skip to content

How the map is drawn

Ryan McAfee edited this page Sep 10, 2026 · 1 revision

How the map is drawn

The detail behind the Map screen. Where the picture comes from, what changed for Valheim 1.0, and how the cache works.

Two halves

The terrain is computed. The markers are read.

Tools/Atlas/WorldGen.cs is a port of Valheim's own world generator, written from the game's own logic: biome placement, the base height noise, rivers and streams, and a height formula per biome. Give it the seed out of the world's .fwl and it produces the same coastlines and mountains the game produces. Valheim does not store a heightmap in the save, so there is nothing to read even if you wanted to.

Everything drawn on top of that is read out of the save. Portals, altars and traders, build clusters, cartography data, the in game clock and the current random event are all real records in the world file.

Deep North and Ashlands

Valheim has two height formulas per biome. A cheap one used only while laying out rivers and streams during pregeneration, and the real one that decides the ground a player walks on. Until 1.0.1, BakaLoader used the pregeneration approximation for both, which is why the northern and southern edges of the map did not match the world people were playing in.

Deep North. 1.0 dropped the rule that promoted high Deep North ground to Mountain, so the whole polar cap is Deep North now. The real formula is flatter and lower: a flat lift instead of the old doubling, half as much bump noise, anything above a plateau pulled back down, and the old gain multiplier gone.

Ashlands. The real formula uses the game's own noise class, ported term for term, and calls its cellular and simplex fractal functions. The shape is a distance band around the Ashlands ring, faded east and west, with five octaves of cellular noise blended on top to carve the coast into lobes and bays that the flat pregeneration formula never had, then scaled by a simplex fractal, then cut by finer noise for the lava cracks.

One wrinkle worth knowing: the game reseeds that noise generator to a fixed value right after building it, so the Ashlands crack pattern is identical on every seed in the real game. That behaviour is reproduced, so only the surrounding base terrain varies by seed.

The old formulas are still in the code, used only for the river and stream pass, the same as the game.

Reading a 1.0 save

A 1.0 world is a folder of chunk files. Portals live in one dedicated chunk, so a portal only read does not touch the rest.

The location list changed shape in 1.0. It used to store a name string and now stores a hash, so the reader carries a lookup table of 178 location name hashes, built and verified against a real 1.0 save. Without it, every altar would be an unnamed marker.

Chunks are read in parallel, capped at the smaller of your core count and 8.

Guards against a corrupt save

A save with a bad length field could ask the reader to allocate the machine's memory. These ceilings stop that, and anything over them is reported as corrupt rather than read:

a save file or chunk file over 256 MB, a compressed zone block over 256 MB, a decompressed one over 1024 MB, a single byte array field over 128 MB, a string field over 64 MB, a chunk claiming more than 50,000,000 objects, an explored bitmap over 64 million cells, and more than 100,000 map pins.

A cartography table's own compressed blob has its own ceiling of 128 MB once unpacked. One that claims to expand past it is left out of the map rather than unpacked, and says so in the log: "a map table says it expands to 4294967296 bytes, past the 128 MB ceiling, so it is left out of the map". The rest of the map still draws.

A world version outside 9 to 41 is refused too, with a message naming the version.

A save landing mid read

The server saves whenever it likes, including while the map is being read.

For a 1.0 world, if a chunk file disappears part way through, the reader checks whether a newer generation has since been committed. If one has, that was a save landing, so it reads the new generation once and reports nothing. If the same generation is still the newest, the file genuinely broke and it says so.

For a legacy world, the .db is briefly absent during the atomic swap, so the reader waits 250 ms and tries once more.

Fog of war

There is no mod free way to know what has been explored except a cartography table. When somebody uses one, their explored area is stored in the world save as a bitmap.

Fog of war is the union of every cartography table's bitmap on the save, baked into a veil image. A world where nobody has ever recorded discoveries on a table has no such record at all, so the whole map stays veiled. That is the honest answer, not a bug.

Pins are narrower. Every table's explored area is merged, but only the first table's pin list is read, so pins on a second table do not appear even though the fog they cleared does.

The cache

Rendered images go to %LocalAppData%\ValheimBakaLoader\AtlasCache and are served to the interface through a virtual host.

The terrain image is named map_{seed}_{size}.png, with a suffix added when a world size mod is detected, carrying that mod's world edge, world stretch and biome stretch values. Without Redraw map, a render is skipped entirely if that exact file already exists. So two worlds on the same seed share one image, and changing a world size mod produces a different name rather than a stale picture.

The fog image is named fog_{world}_{save timestamp}.png. Keying it on the save file's own last write time means a new save automatically produces a new name, so the fog is never stale and nothing has to remember to delete anything.

Nothing prunes that folder. Every distinct seed, size and save timestamp leaves a file behind. If it gets large, delete it. It is rebuilt on demand.

The other biome cache

Valheim itself writes {world}_biomedatacache.bin into a cache folder beside the save folder. It belongs to the game. Nothing in the map reads it.

It matters only when a world is copied, renamed or deleted, because the cache has to travel with the world or go with it. BakaLoader keys it on the world name stored inside the .fwl or .fwl2 rather than the name of the file on disk, because those two differ after a copy or a rename. 1.0.1 corrected that key to match how the game keys the file.

Limits

The render size is clamped between 256 and 4096 pixels, defaulting to 2048.

Only one render and one world scan can run at a time. A second one while one is in flight is refused rather than queued: "A map render is already in progress." or "A world scan is already in progress."

There is no timeout on a render. It runs to completion in the background and reports progress as a percentage. Ashlands pixels are the expensive ones, because of the noise octaves.

Weather

The forecast is worked out in the interface, from the same maths the server runs. No mod, no hook.

Valheim rerolls weather every 666 in game seconds from a seeded random number generator, seeded by the time period index. Wind comes from four re-seeded octaves. Both are deterministic, so given the world clock, the next few periods can be computed exactly.

The clock it starts from is the netTime stored in the save, plus real elapsed time only while players are online. An empty dedicated server pauses world time, and logging out forces a save, so with nobody on, the saved value already is the current value. That is what the note under the forecast is telling you: "Time stands still: no vikings ashore." or "Anchored to the last world save."

Each biome has its own weighted weather table and its own wind intensity range, which is why the biome rows differ.

Clone this wiki locally