You are viewing a potentially older version of this package. View all versions.
MidnightMods-AsyncSave-0.7.0 icon

AsyncSave

Moves Valheim's world and character saves off the main thread, so saving no longer freezes the game.

Date uploaded a week ago
Version 0.7.0
Download link MidnightMods-AsyncSave-0.7.0.zip
Downloads 1012
Dependency string MidnightMods-AsyncSave-0.7.0

This mod requires the following mods to function

denikson-BepInExPack_Valheim-5.4.2351 icon
denikson-BepInExPack_Valheim

BepInEx pack for Valheim. Preconfigured with the correct entry point for mods and preferred defaults for the community.

Preferred version: 5.4.2351

README

AsyncSave

AsyncSave moves Valheim's world and character saves off the main thread, so a save no longer freezes the game. Nothing about the save format changes — the bytes it writes are the bytes vanilla would have written.

The two halves are independent and neither syncs anything over the network, so the same DLL runs unmodified on a dedicated server, a client, or a host, any mix is supported.

How it works

World save (server or host)

Vanilla's ZNet.SaveWorld clones every ZDO in the world into a fresh list, on one frame, and only then hands it to the writer thread. AsyncSave replaces that with a coroutine that walks ZDOMan's sectors across many frames, serializing each ZDO straight into a reusable buffer, while the writer thread waits on it.

Character save (anywhere there is a local player)

Vanilla's minimap save writes 8.4 million individual booleans through a BinaryWriter, then gzips the result and writes the .fch synchronously. AsyncSave bulk-copies the explored arrays (two memcpys producing the identical byte sequence), then hands compression, hashing and the file write to a background worker. The parts that touch Unity-owned or gameplay-mutated state stay on the main thread.

The character save made on quit, logout and shutdown still runs synchronously and in full before the scene goes away, so it is never in flight; only its minimap step uses the bulk copy.

Automatic stand-downs

If the mod cannot safely run — it fails to patch ZNet.SaveWorld, the .fch layout is not the one this build was written against, the revision hooks are missing, or the host is big-endian — it disables the affected half or falls back to FullScan for that session only and logs why. Your config file is never rewritten, so the setting you chose is still there next launch.

Requirements

BepInEx. No dependencies on other mods. Incompatible with SmoothSave (they patch the same paths); BepInEx will refuse to load both.


If you enjoy my mods donations are appreciated. My mods will never be paid and donations are not required.

Support me on Ko-fi

CHANGELOG

0.7.0

The save log line now says where the world is stored and how much of a slow save was the game's own world backup, so a slow save on cloud storage is no longer pinned on the mod.
The first save after a world loads no longer stalls while the mod sets up its working memory, which now happens on the loading screen.
Logging out or quitting is a little quicker, as the character save made then now copies the map in bulk.
Background character saves now sync achievement progress and check cloud storage space the same way the game itself does.

0.6.1

Updated for the latest Valheim patch, so character saves run in the background again.
World saves now also cover parts of the world that had never been saved before, matching a fix in the game itself.

0.6.0

Adds support to enable Async save running the final shutdown save. This can prevent crashes during shutdown for servers which have large ZDO counts

0.5.0

Rebuild for Deep North!

0.4.0

Prune the server's dead-ZDO table instead of letting it grow for the whole session.

Vanilla records every destroyed ZDO in ZDOMan.m_deadZDOs and only clears it when a world
loads, but reads it for one purpose: rejecting a create for a ZDO that died while a client's
packet was still in flight. On a large world that is millions of retained entries answering a
question about the last few seconds - a dictionary that is rehashed as it grows and walked by
every gen-2 GC.

Entries now expire after a configurable lifetime (default 60s). Pruning is O(expired) with no
scan of the table, and is server-side only.

0.3.0

Initial release.