Skip to content

Releases: Akoozie/ValheimTune

ValheimTune 0.7.0 — Valheim 1.0 support

Choose a tag to compare

@Akoozie Akoozie released this 09 Sep 16:16

Server-side BepInEx plugin for Valheim dedicated servers. Players install nothing.

This binary is byte-for-byte the one running on the reference server — same sha256, no separate release build.

sha256  98440ca31f5b4d807d5be53f519a22b1524c7890eca7e5c6a5f12513c43a48b3

Compatibility

game            1.0.7 (network version 39)
server build    25185644 (Steam app 896660)
needs           BepInEx 5.4.x for Valheim

On any other game version the plugin runs in vanilla + measurement mode and says so in the log. Still on 0.221.12? Use 0.6.0.

⚠️ Upgrading from 0.6.0 — read this or the plugin will do nothing

BepInEx reads your existing config file, not the new defaults. Your akoozie.valheimtune.cfg still says:

[Compat]
KnownGoodBuilds = 0.221.12

On game 1.0.7 that fails the version gate and every replacement patch silently disables itself — the log says replacements OFF and the plugin measures vanilla while looking perfectly healthy. Edit it before or after copying the DLL:

[Compat]
KnownGoodBuilds = 1.0.7

The now-orphaned [Save] SlicedSave and [Save] SaveSliceMs keys are harmless; BepInEx ignores them. You can delete them or leave them.

What changed for Valheim 1.0

Sliced save removed — 1.0 does it better

ZDOMan.SaveAsync no longer exists. Valheim 1.0 rewrote world saving to write one file per chunk and clone only the dirty chunks. Measured on a 698,746-object world, idle:

                          first save (50/50 dirty)   next save (0/49 dirty)
chunk writing                     2,713 ms                   3 ms
clone (GetSaveClonePerChunk)        187 ms                   6 ms

That is a strictly better answer than slicing the clone across frames, so SlicedSave and SaveSliceMs are gone rather than ported. Vanilla now handles it.

Dirty sets re-pointed at the new simulation distance

1.0 removed ZoneSystem.m_activeArea / m_activeDistantArea and the three-argument ZNetScene.InActiveArea. The sync radius is now a per-peer SimulationDistance, clamped server-side to min(client request, server cap). The dirty-set area test was rewritten to mirror the ring predicate in ZDOMan.FindSectorObjects.

Also

  • Version.m_networkVersion renamed to Version.c_networkVersion
  • [Compat] KnownGoodBuilds default is now 1.0.7
  • 11 patched methods, down from 15 (the four save-path patches are gone)

Everything else — top-K selection, relay throttle, receive cap, Steam send rate, target frame rate, deferred asset unload, render-mesh skip, the watchdog and the stats line — rebuilt unchanged. ZRpc.cs and ZSteamSocket.cs are byte-identical between 0.221.12 and 1.0.7.

Verified live on 1.0.7

Deployed 2026-09-09 with a player online, 698,748 objects:

[ValheimTune] 0.7.0 loaded on game 1.0.7 (net 39), 11 methods patched, replacements on
[ValheimTune] SendZDOs window 32768/4096, 3 constants replaced (expected 3)

syncList avg 0.07–0.11 ms      frame avg 16.7  max 17.0 ms (60 fps)
Sync cost per call
vanilla 0.221.12 4.1 ms
dirty sets on 0.221.12 0.07 ms
dirty sets on 1.0.7 0.09 ms

The rewritten area test was also checked the way counters cannot check it: healthy numbers are equally consistent with an area test that silently drops objects, so the base was walked and confirmed complete before shipping.

SkipRenderMesh fired for the first time on 1.0 (meshSkips 34) — 1.0's zone generation finally gives it ungenerated terrain to skip. It remains default off pending a longer exploration run.

G1 verified after release — every feature is now live-tested

DeferAssetUnload remains default off, but it has now been observed working on 1.0. The hour boundary landed with a player connected:

[ValheimTune] asset unload deferred: 1 player(s) online, will run when the server empties (backstop 240 min)

Frames across the boundary held 16.9-24.6 ms at 60 fps - none of the 443-607 ms Resources.UnloadUnusedAssets() stall measured on 0.221.12. Turn it on with [Server] DeferAssetUnload = true if hourly hitches bother your players.

Known remaining cost (vanilla, not this plugin)

ZDOExtraData.PrepareSave is byte-identical to 0.221.12 and still clones eight maps on every save regardless of how little changed. Measured on 1.0.7 with a player online, one dirty chunk out of 49:

clone                        32 ms   main thread
ZDOExtraData.PrepareSave    204 ms   main thread
chunk writing               142 ms   writer thread
-> frame max 243 ms

The plugin does not patch this. It is the best-evidenced target left, and a fix is not simply reinstating the old sliced-save prefix - that clone is what keeps the writer thread safe.

Install

Drop ValheimTune.dll into BepInEx/plugins/ on the server. Nothing goes on clients. Full config reference and the stats-line guide are in the README.

ValheimTune 0.6.0

Choose a tag to compare

@Akoozie Akoozie released this 08 Sep 09:28

Server-side BepInEx plugin for Valheim dedicated servers. Players install nothing.

This binary is byte-for-byte the one running on the reference server — same sha256, no separate release build.

Compatibility

game            0.221.12 (network version 36)
server build    21981590 (Steam app 896660)
needs           BepInEx 5.4.x for Valheim

On any other game version the plugin runs in vanilla + measurement mode and says so in the log. New in this release: the README now explains what to do when that happens — previously it pointed at a porting doc written for maintainers, which was no help to a server admin.

New in 0.6.0 — G1, deferred asset unload

Vanilla calls Resources.UnloadUnusedAssets() every hour, regardless of whether anyone is playing:

// src_server/Game.cs:239
InvokeRepeating("CollectResourcesCheckPeriodic", 3600f, 3600f);

Measured on a 698,000-object world:

Unloading 2 unused Assets  ... 607 ms
Unloading 1 unused Assets  ... 456 ms
Unloading 0 unused Assets  ... 443 ms     <- frees nothing, still 443 ms

The cost has nothing to do with what it frees — Unity's MarkObjects walks all ~207,000 loaded objects to release one asset. It was caught landing with two players online at frame max 512 ms against a 17 ms baseline.

Both vanilla entry points route through Game.CollectResources, so one prefix covers them.

[Server]
DeferAssetUnload = false           # default
AssetUnloadMaxDeferMinutes = 240

Deferred, not skipped. Memory hygiene still matters — the collection runs the moment the last player disconnects, or after the backstop if your server never empties.

Honest status: this ships off and is not yet verified in the field. It is live on the reference server with the knob on, but proving it requires a player online across an hour boundary, which has not happened yet. With an empty server the deferral is a no-op. If you turn it on, look for asset unload deferred: N player(s) online in your log, then asset unload running after N s deferred once everyone leaves.

SkipRenderMesh from 0.5.0 is likewise still off and still unproven — it only fires on terrain that has never been generated, which an explored world does not have.

Everything else, unchanged from 0.5.0

690,000 objects, a 12,000-instance base, 2-6 players, on a 4-core laptop:

Vanilla ValheimTune
Sync scan, per player per round 4.1 ms 0.07 ms
Autosave 381 ms freeze in one frame 6 ms slices over ~350 frames
Join sync cost ~11 ms per call ~5.5 ms
Join stream rate 1,261 objects/s 3,617 objects/s
Server frame rate 30 fps, hard-capped 60 fps

Full history in CHANGELOG.md.

Verify the download

sha256  b351d8958020dcb9225e349701ec259df844484d270b97b9a43f4d39c085254d
size    51,200 bytes

MIT licensed. Not affiliated with Iron Gate or Coffee Stain.

ValheimTune 0.5.0

Choose a tag to compare

@Akoozie Akoozie released this 07 Sep 21:01

Server-side BepInEx plugin for Valheim dedicated servers. Players install nothing — every change is on the server and the wire format is untouched, so vanilla clients connect exactly as before.

Compatibility

game            0.221.12 (network version 36)
server build    21981590 (Steam app 896660)
needs           BepInEx 5.4.x for Valheim

On any other game version the plugin runs in vanilla + measurement mode and says so in the log — it will not silently apply old patch logic to new code.

Install

  1. Install BepInEx on the server. With the lloesche/valheim-server Docker image that is BEPINEX=true in server.env.
  2. Drop ValheimTune.dll into BepInEx/plugins/ (Docker: config/bepinex/plugins/).
  3. Restart. The config appears at BepInEx/config/akoozie.valheimtune.cfg.

Confirm in the log:

[ValheimTune] 0.5.0 loaded on game 0.221.12 (net 36), 14 methods patched, replacements on

Then apply the recommended settings one at a time.

Measured on the reference server

690,000 objects, a 12,000-instance base, 2-6 players, on a 4-core laptop.

Vanilla ValheimTune
Sync scan, per player per round 4.1 ms 0.07 ms
Autosave 381 ms freeze in one frame 6 ms slices over ~350 frames
Join sync cost ~11 ms per call ~5.5 ms
Join stream rate 1,261 objects/s 3,617 objects/s
Server frame rate 30 fps, hard-capped 60 fps

New in 0.5.0

[Server] SkipRenderMesh — a headless server rebuilds terrain render meshes it never draws. This prefixes Heightmap.RebuildRenderMesh and skips it; the collision mesh, paint mask and material instance are untouched.

It ships off, and honestly unproven. On the reference server the prefix attached but the new meshSkips counter stayed 0 across a five minute exploration run, because the server only instantiates a heightmap for ground that has never been generated and an explored world has none. Leave it off until you see meshSkips climb.

Everything else in this release is unchanged from 0.4.2. Full history in CHANGELOG.md.

Verify the download

sha256  d1d49249b66f09acdc873a1098411eb8ca16ec4d78438f26abfcc9481581cded
size    48,640 bytes

MIT licensed. Not affiliated with Iron Gate or Coffee Stain.