You are viewing a potentially older version of this package. View all versions.
Sarkastic_gg-Dedicated_Simulation-1.18.3 icon

Dedicated Simulation

Server-side BepInEx plugin for Valheim dedicated servers: the server simulates the world itself. Character guard, item ledger, portal lock, fire control, location icons, network limits. Fork of Serverside Simulations by ddormer; clients stay vanilla.

Date uploaded a day ago
Version 1.18.3
Download link Sarkastic_gg-Dedicated_Simulation-1.18.3.zip
Downloads 34
Dependency string Sarkastic_gg-Dedicated_Simulation-1.18.3

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

Sarkastic.gg Dedicated Simulation

version: 1.18.3 players: vanilla clients Valheim: 1.0.16 BepInEx: 5.4.2351 license: MIT (own code)

Source code · Report a bug · Changelog · Resource Regrowth

Join us on Discord Support us on Patreon

Fork of Serverside Simulations by ddormer, which is no longer maintained as of 2026, renamed at the original authors' request. Updated for Valheim 1.0, building on ddormer/valheim-serverside#118 by @mreastman.

The dedicated server simulates the world — monsters, physics, ships without a driver — instead of handing each area to whichever player got there first. Server-side only: players keep vanilla clients.

Companion plugin: Resource Regrowth (Thunderstore) brings back surtling cores, chest loot, creatures and whole zones in areas left alone; the two are made to run together.

Updated for Valheim 1.0.16. Up to version 1.12 it was also checked on 1.0.15 and 1.0.12; what was added after that is tested on 1.0.16 only. A startup check warns about every vanilla method the mod uses that a game update has changed.

Why, compared to vanilla

In vanilla, the first player to enter an area owns it: their game runs the monster AI and physics there, and everyone else nearby sees that area through them. If that player has a poor connection or a slow PC, everyone around suffers — monsters jump around, hits land late — and updates travel from each player to the server, on to the owner and back.

With this mod the server owns and simulates those areas:

  • Each player depends only on their own connection to the server, not on someone else's.
  • Clients no longer run AI and physics for the areas they would have owned, which helps slower PCs.
  • Ships are handed to their driver, so steering has no round trip.

What it costs:

  • The server needs more CPU, RAM and upload than a vanilla server.
  • A player alone in an area now has their round trip to the server where vanilla would have had none. With a nearby server this is rarely noticeable.

Observed on one server

Valheim 1.0.7, Windows dedicated server, up to four players, September 2026. One group's session, not a benchmark.

  • No exceptions or mod warnings during play.
  • Items picked up from the ground: 98% of 437 on the first ownership request (1.2.0), 214 of 214 (1.5.0); the rest within 2 s.
  • The per-player send queue was full in at most 0.2% of send ticks, only in bursts such as portals.
  • About 0.8 of a CPU core on average with one player, and 15–25% of a core while empty (with the job worker cap). RAM about 1.6 GB empty, 2–2.6 GB with players, levelling off.

Not covered yet: Frost Foundry, sailing, raids, Deep North events, a non-default -simulationdistance, and the console commands under a Windows server panel.

What this fork adds

Compared to Serverside Simulations 1.1.9 (details in the changelog):

  • Valheim 1.0 support, and a review of every patched method against the 1.0 code.
  • Fixes: location prefabs were never released (a memory leak); zones could be generated before their locations; no objects were created with a non-classic -simulationdistance; 1.0 errors on the server with ship sails, the Frost Foundry (which duplicated items) and leviathans; the far ring of unexplored land was not pre-generated as in vanilla, so distant trees, cliffs and the Mistlands mist appeared late.
  • Objects nearest to a player are created first, e.g. after a portal.
  • Server-side networking limits from BetterNetworking, with a per-player log of how often they are reached.
  • Cap on Unity job worker threads, which otherwise idle at CPU cost on many-core hosts.
  • Fix: player changes that the save skipped. Valheim 1.0 rewrites only the world chunks it marked as changed, and a change received from a player marks nothing, so what a player just built or moved could be missing after a restart.
  • Fix: teleported players left behind as ghosts. A player who portalled or respawned stayed visible to the players near the old spot, frozen, until they next crossed a zone line, because Valheim 1.0 checks whether an object left their area before it stores the new position.
  • Fix: fireplaces smothered for everyone but the server. A smoke source only puffs while the local player is within 64 m, and a dedicated server has none, so the server never saw smoke: a fireplace in a room full of smoke, which every player sees go out, kept burning on the server -- using fuel, throwing sparks and setting what touches it alight -- and a fire under a roof never choked.
  • Admin commands on the server console: give <item> <amount> <player>, broadcast <text>, event <name> <player>, players, characters, allow <name>, save, stop, typed into the panel the server runs in (AMP), and anything else goes to the game's own console (kick, ban, banned, stopevent, setkey, removekey, and after devcommands the cheats that need no player: skiptime, listkeys, resetkeys ...). A vanilla dedicated server never reads its console, and Valheim 1.0 does not let a player on a dedicated server use spawn from the game console, admin or not.
  • Smoother server frames: world updates reach every player at a steady interval however many are online, one slow frame no longer makes the next one slow through physics catch-up, and new zones are generated one per tick instead of one per exploring player. A periodic log shows frame times and what they are spent on.
  • save and stop console commands for server panels that write to standard input.
  • Character guard (off by default): a check on the characters players join with, server-side only, so clients stay vanilla. A character this world has not seen must be fresh, and a known one that comes back changed was played elsewhere -- see below.
  • Item ledger (off by default): an account per character of the items that lock progress, what it got here and what it put back into the world; items that came from another world are logged, or taken away -- see below.
  • Night spawn guard (off by default): the spawns that come with boss progress (Greydwarfs, Draugr, Skeletons, Goblins, Seekers, Charred, ...) held back around a player who has not got that far themselves, even where the world as a whole has moved past it -- see below.
  • Guardian stones (off by default): a boss's trophy on its guardian stone, and so its power, only for players who have beaten that boss themselves; to everyone else's game the stone is empty -- see below.
  • Fire control (off by default): a limit in metres on how far fire spreads from its source, a cap on spark generations, fireplaces that never set what touches them alight, or fire from projectiles only, so a player's own build never sets it on fire -- with the reach of every fire source in the game worked out, and every fire and fireplace simulated by the server so the rules hold -- see below.
  • Portal lock (off by default): a pair of portals used only by those it belongs to -- the builders, or the owner and the players on the ward over it; a name starting with * is open to everyone. Two portals are paired only if both builders may use the pair, so a portal built with the name of someone's unpaired one no longer walks anyone into their base -- see below.
  • Location icons (off by default): a trader's (Haldor, Hildir, the Bog Witch) and other locations' map icons only for players who have found that place themselves; vanilla shows them to everyone the moment anyone's presence has generated the zone -- see below.
  • Processor placement (off by default): the server pinned to one chiplet of an AMD EPYC or Ryzen (a die with its own L3 cache), the least busy one at startup, or to processors you name, and a higher process priority.
  • Safety: a startup check warns when a vanilla method the mod replaces has changed in a game update; if the core patches cannot be applied, the mod removes itself and the server runs vanilla.

Installation

  1. Install BepInExPack_Valheim 5.4.2350 or newer on the dedicated server.
  2. Copy SarkasticGG_Dedicated_Simulation.dll from the latest release into BepInEx/plugins/.
  3. Back up the world and restart the server. BepInEx/LogOutput.log should show Sarkastic.gg Dedicated Simulation installed and Vanilla drift check passed.

Clients need nothing.

Upgrading from Serverside Simulations: delete Serverside_Simulations.dll. Both use the same plugin GUID, so only one can load; the config file MVP.Valheim_Serverside_Simulations.cfg carries over.

Do not also run BetterNetworking on the server: its server-side limits are built in.

Configuration

BepInEx/config/MVP.Valheim_Serverside_Simulations.cfg, read at startup:

Setting Default
[General] Enabled true Turn the mod off without removing it.
[MaxObjectsPerFrame] Enabled true Turn the object creation limit off (vanilla's 100 per frame stays).
[MaxObjectsPerFrame] MaxObjects 100 Objects the server creates per frame, 1 to 10000. A vanilla dedicated server creates 100; higher loads areas faster at more CPU, lower fills them in more slowly.
[Networking] Enabled true Raise the limits on how fast the server sends world data to each player (the server side of BetterNetworking). Needs a restart.
[Networking] QueueSizeKB 48 Data queued per player before the server holds world updates for that tick (Valheim: 10). 48 KB at 20 ticks/s is about 960 KB/s, just under the send rate cap; above 80 Steam starts failing.
[Networking] SteamSendRateMinKB / MaxKB 256 / 1024 Steam send rate per player, KB/s (Valheim: 150). Keep min × players below the server's upload.
[Networking] StatsIntervalMinutes 5 How often to log, per player, how often the send queue was full. Near 0% means the limits are not what holds you back. 0 disables.
[Server] CpuAffinity (empty) Processors the server runs on. Empty: wherever the system puts it. auto: one chiplet -- on AMD EPYC and Ryzen a die with its own L3 cache (on the first EPYC generation also its own memory) -- the least busy over one second at startup, read from the system's own topology (Windows: processor dies, else NUMA nodes, else L3 groups; Linux: /sys), within the processors the process may already use. Or a list such as 16-31 or 0-7,32-39. Processors above 63 are not used. Keep UnityJobWorkers below the chiplet's processor count. Needs a restart.
[Server] ProcessPriority Normal Normal, AboveNormal or High: the server's priority against everything else on the host (Linux: nice -5 / -10, which needs CAP_SYS_NICE). Needs a restart.
[Server] UnityJobWorkers 8 Upper limit on Unity job worker threads (Unity: one per CPU core). Only ever lowers the count; 0 leaves Unity's default.
[Server] ConsoleCommands true Read commands from standard input: save, stop (saves first), players, give <item> <amount> <player> (drops the items in front of that player; the name may be a unique beginning), broadcast <text> (a message in the middle of every player's screen), event <name> <player> (a raid at that player; events lists them), help; anything else goes to the game's own console. In AMP this is its console, see the AMP chapter.
[Server] MaxGiveAmount 1000 Most items one give drops.
[Server] ConsoleInputCodePage 1250 How a console line that is not valid UTF-8 is read (UTF-8 is always tried first): 1250 Central European, 852 Central European DOS, 1252 Western, 65001 UTF-8 only. The log shows the bytes the first time it matters.
[Performance] SendIntervalMs 100 How often each player gets world updates. Valheim serves one player per frame, so with N players each waits N+1 frames (330 ms at 15 FPS with 4 players). Each send costs server CPU; see the performance log. 0 keeps Valheim's behaviour.
[Performance] MaxCatchUpMs 100 Longest frame counted in full. After a slow frame Unity reruns physics and every creature's fixed update for each 20 ms missed (Valheim allows 200 ms, 10 times); 100 caps it at 5. Game time runs slightly slow during such frames. 0 keeps the game's setting.
[Performance] MaxZonesPerTick 1 New zones generated per zone tick (10 per second), players taking turns. 0 = one per player per tick, as before.
[Performance] ServerTargetFps 60 Frame rate the server aims for (the game sets 30). With time to spare a frame no longer waits 33 ms, so reactions to players halve; under load it changes nothing. 0 keeps 30.
[Fixes] SaveClientChanges true Count a change that arrives from a player as a change to its world chunk, so the next save writes it. Valheim 1.0 rewrites only changed chunks and skips those.
[Fixes] TeleportGhosts true Tell the players near the old spot to drop a player who teleported away. Valheim 1.0 checks whether an object left their area before it stores the new position, so the teleported player stayed there for them, frozen, until they next crossed a zone line.
[Fixes] ServerSmoke true Let fires and fireplaces make smoke on the server while a player is within 64 m, as they do on that player's computer in vanilla: a fireplace in a smoke-filled room goes out on the server too, and fires under a roof can choke (see Fire control below).
[Fixes] DungeonLoadGuard true Keep a dungeon whose room bundle fails to load from wedging its zone. When Unity refuses a bundle as already loaded, the game still reports the load as done and then throws, so the dungeon never spawns and its zone stays flagged as loading. The guard uses the bundle Unity already holds, reports a load that really failed as failed, and lets such a dungeon go so it is tried again next time. A vanilla dedicated server never loads dungeons; this mod does.
[Compat] ValheimCommunityPatchUnload false Only with ValheimCommunityPatch installed. Its zone-diff unload drops objects outside the simulation distance of the server's reference position -- the world origin -- so objects around players are destroyed and created again on every pass. Off: that patch of it is removed when the world starts. On: it is kept, and the object lists are marked as edited on every pass so it takes the game's own unload check.
[Compat] ValheimCommunityPatchSpawnQueue false Only with ValheimCommunityPatch installed. Its spawn queue orders new objects by distance from the world origin, so this mod's nearest-player ordering never runs. Off: that patch of it is removed when the world starts. On: it is kept.
[CharacterGuard] Enabled false Check the characters players join with (see Character guard below).
[CharacterGuard] NewCharacters RequireFresh RequireFresh: a character this world has not seen must still be ready for Eikthyr's raid and wear nothing beyond a level 1 workbench. Allow: every new character is let in and remembered.
[CharacterGuard] NewCharacterAction Kick For a new character that is not fresh: Kick (after a message on their screen), Log or Ignore.
[CharacterGuard] ChangedAway Log For a known character that comes back wearing something new or with other progress: Log, Kick or Ignore.
[CharacterGuard] ExemptAdmins true Admins are never checked.
[CharacterGuard] FreshEvent army_eikthyr The raid a fresh character is still ready for. The game stops that once a character knows the antler, the bronze or iron pickaxe, hard antler or Eikthyr's trophy.
[CharacterGuard] NewCharacterMessage / ChangedAwayMessage (English text) Shown in the middle of the player's screen before the kick.
[CharacterGuard] Welcome false Greet a character the first time it joins this world.
[CharacterGuard] WelcomeTitle / WelcomeLines (English text) The greeting in the middle of the screen, then the lines (separated by |) in the top left corner.
[ItemLedger] Mode Off Off, LogOnly or On: keep item accounts per character (see Item ledger below); On also takes away items that came from another world.
[ItemLedger] Items auto auto: the items that lock progress, from the game's own data (see below). Or item prefab names, comma separated. Items traders sell are always left out.
[ItemLedger] ExtraItems / ExcludeItems (empty) Item prefab names to add to the list, or never to keep accounts of.
[ItemLedger] LogAllMovements false Also log every movement of a tracked item (and every craft the ledger counts), not only what cannot be accounted for.
[ItemLedger] ExemptAdmins true Admins get no account and are never checked.
[ItemLedger] GraceHours 168 For this long after the ledger first runs on a world, no character counts as new: the players who are already around come back with what they had.
[ItemLedger] Message / AltarMessage (English text) Shown in the middle of the player's screen when items are taken away, or a boss altar refuses them.
[NightSpawnGuard] Enabled false Hold back the spawns that come with boss progress until every player in the spawn zone has got that far themselves (see Night spawn guard below).
[GuardianStones] Enabled false Show a boss's trophy on its guardian stone, and so offer its power, only to players who have beaten that boss themselves (see Guardian stones below).
[GuardianStones] ExemptAdmins true Admins see every stone as it is.
[GuardianStones] Message (English text) Shown to a player standing at a stone that holds a trophy they may not use, at most once a quarter of an hour per stone; {0} is the boss. Empty: no message.
[PortalLock] Enabled false Let a pair of portals be used only by those it belongs to (see Portal lock below).
[PortalLock] ExemptAdmins true Admins may use and rename every portal.
[PortalLock] PublicPrefix * A portal whose name starts with this is open to everyone. Empty: none.
[PortalLock] ExtraReach 0 Metres added to a ward's own radius (32 m for the game's ward) when deciding whether it covers a portal.
[PortalLock] Message / PairingMessage (English text) Shown at a portal a player may not use, and to the builder of one that cannot be paired, at most once a quarter of an hour per portal.
[LocationIcons] Enabled false Show a location's map icon (Haldor, Hildir, the Bog Witch, Hildir's dungeons, the Deep North boss room, the ancient upgrade station) only to players who have been near it themselves; remembered per character in <world>.icons.txt. The start temple's icon stays for everyone.
[LocationIcons] DiscoverRadius 50 How near (metres, horizontally) a player must have been to a location for its icon to appear on their map.
[FireControl] Enabled false Limit how far fire spreads (see Fire control below). With the three settings below at their defaults it changes nothing.
[FireControl] MaxRadius -1 A fire starts only within this many metres (straight line) of the source its chain began at. -1: no limit.
[FireControl] MaxSpread -1 Caps how many further generations of sparks any fire may set off. 0: nothing throws sparks except an arrow or fireball where it lands. -1: as in the game.
[FireControl] FireplaceIgnition true Lit fireplaces set alight whatever burnable touches their flame. Off: a hearth, brazier or torch never starts a fire; a bonfire or campfire still throws sparks.
[FireControl] OnlyProjectiles false Only projectiles start fires -- a fire arrow, a Staff of Embers fireball, a meteor, a lava rock -- and what they set alight burns and spreads as before (within MaxRadius and MaxSpread). Nothing a base has (fireplaces, the fires they lit, the troll a player summons) throws a spark or sets anything alight. Surtlings' and fuling shamans' fireballs never set anything alight in the game.
[Performance] StatsIntervalMinutes 5 How often to log FPS, frame times, physics steps per frame, the cost of world updates and zone generation, and what the slowest frame was doing, while players are online. 0 disables.

Character guard

Valheim keeps a character on the player's own computer and a vanilla client never sends its inventory to the server, so no server-side mod can read or replace what a character carries. The server does see a character's id (the same on every world), what it wears and holds (both hands, back slots, armour, utility, trinket, with the upgrade level of weapons), and the raids it is ready for, which the game works out from the items the character knows and the bosses it has beaten. The guard uses that:

  • New characters -- not in this world's list and without anything built, a bed or a tombstone here -- must be fresh: still ready for Eikthyr's raid (the game stops that once a character knows the antler, bronze or iron pickaxe, hard antler or Eikthyr's trophy) and wearing nothing beyond what a level 1 workbench makes. A character brought in with progress from another world gets a message and is kicked 8 seconds later (NewCharacterAction).
  • Known characters that come back wearing something past a level 1 workbench they did not have when last seen here, or ready for other raids than then, were played somewhere else in between; that is logged (ChangedAway, or kicked). A club or rags are made anywhere in minutes and tell nothing. What an online character wears and knows is noted every minute, at every world save and at shutdown, as well as when it leaves, since a server shutdown does not disconnect the players one by one.
  • Welcome (Welcome, off by default): a character let in for the first time gets WelcomeTitle in the middle of the screen and then each of WelcomeLines in the top left corner, a few seconds after joining. A kicked character gets its kick message instead.
  • Characters that built something or own a bed or a tombstone in the world count as known, so switching this on does not lock out existing players. Admins are exempt.
  • characters on the console shows how the guard sees who is online; allow <name> lets a character in (and one that is waiting for its kick stay). The list is <world>.characters.txt next to the world save.

What a character carries without wearing it stays invisible to the server: this stops characters being imported with their progress; the item ledger below catches materials brought in by known characters once they reach the world.

Item ledger

The server never sees a bag, but nearly every way into and out of one passes through an object it does see:

  • In: picking an item up (the player takes it over and deletes it), taking it out of a chest, cart, ship or tombstone, or off an item stand or armour stand.
  • Out: dropping it, putting it into a container or on a stand, feeding it to a smelter, kiln, refinery, cooking station or fermenter, offering it at a boss altar, building with it, dying with it (the tombstone is the whole bag). A drop counts only if the item has been in a bag: the game marks everything in a bag, and what falls out of a destroyed piece, a creature or a rock carries no mark.
  • Worn: what a character wears and holds is checked every few seconds; an upgrade shows as a higher quality.

Crafting, upgrading, eating, buying from a trader and what a caught fish brings along are not seen. So a tracked item the character never got here counts as crafted if its recipe can be paid from the tracked items it did get, and the ledger reckons in the player's favour wherever the game leaves room: a craft at a station yields the most the crafting bonus can give (three more per craft for a lucky batch of five), an upgrade may have been made at Valheim 1.0's upgrade station, which takes only upgrader items, an item it held may have broken there and handed part of its materials back, and a caught fish counts in the most its extra drops can bring (a Fish10 one silver). What traders sell is not tracked.

Which items: Items = auto takes the items that lock progress, from the game's own data: what cannot go through a portal (ores, metals, dragon eggs), what bosses drop and what summons them, every material that all recipes and pieces using it need more than a level 1 workbench for, and every item that all its recipes need more for -- what a forge, cauldron, black forge or galdr table makes, and what goes into it. In Valheim 1.0.16 that is about 530 items; the guard log lists them by reason at startup.

When a character puts more of an item into the world than it ever got here, and could have made, the rest came from somewhere else. That is written to <world>.guard.log next to the world save; with Mode = On it is also taken away -- a dropped stack is cut down, a container or stand loses it once nobody uses it, a smelter drops it from its queue, a boss altar refuses to summon -- and the player sees a message. What was built with it, put on a cooking station or fermenter, or is worn is only logged.

  • A new, fresh character (see Character guard) starts at zero, so its account is exact from the start.
  • For any other character, what it carried when counting began is unknown. Its findings are logged as unverified and never acted on, until its first death here: the tombstone shows the whole bag, and from then on its account is exact.
  • For the first GraceHours after the ledger first runs on a world, no character counts as new.
  • The accounts are kept in <world>.items.txt.
  • A fault in the ledger or the guard is logged (at most 20 times in a quarter of an hour) and never stops the game's own code. If the accounts or the known characters cannot be read, that feature stays off until the next start and leaves the file as it is.

Start with LogOnly for a while and read the guard log before switching to On.

Night spawn guard

Some of Valheim's ambient spawns come with boss progress: Greydwarfs at night in the Meadows once Eikthyr is dead; Draugr, Greydwarf Elites and Shamans, and Odin's night visits, once the Elder is; Skeletons once Bonemass is; Goblins (the hostile wandering kind) once Yagluth is; Seekers, Seeker Brood and Ticks once the Queen is; Charred once Fader is. Vanilla gates each one by a single world-wide key, set the moment any player beats that boss anywhere: a new player can meet Seekers in the Meadows because someone else on the server has been to the Mistlands.

The guard holds such a spawn back in a zone -- the 64x64 m area vanilla spawns around; a spawn is placed 40-80 m from one of the players in it -- until every player in that zone has got that far themselves. Until then the spawn behaves there exactly as in a world where the boss still lives. In a group the least progressed player decides. Raids are not affected: with -setkey playerevents the game already picks raid targets by each player's own progress.

How far a player has got is read from the one thing a vanilla client tells the server about its progress: the raids it is still "ready for", which the client works out from the items it knows and its own keys (possibleEvents, the same list the character guard reads). The main raids form a chain -- each needs the previous boss's drop known and stops once the next boss's is -- so the first one still listed tells how far the player is. The forest troll and surtling raids, which need the Elder's and Bonemass's drop actually known, confirm those two steps, because the chain raids also stop for a player who merely took that boss's power at a stone, where someone else may have hung the trophy.

Checked against a port of the game's own raid check over its raid data (1.0.16): exact for every progress level, and no combination of other people's powers lifts a player at or below the Elder. Above that, a player looks further than they are only by taking the Queen's power and every power before it in the chain (from Bonemass's level Moder's too, from Moder's Yagluth's). A player counts a boss as beaten once they have picked up one of its drops: for Eikthyr the trophy or a Hard Antler, for the Elder the trophy or the Swamp Key, for Bonemass the trophy or the Wishbone (everyone at those two kills gets their own key and wishbone), for Moder the trophy or a Dragon Tear -- but for Yagluth only a Torn Spirit (or a Wisp or Demister from the Mistlands) and for the Queen only a Majestic Carapace, not their trophies. Fader leaves nothing of his own in the list, so his Charred count as the Queen's. A player whose list has not arrived yet counts as having beaten nothing. The Deep North's Jotun patrols are left as vanilla.

Guardian stones

A boss's power is taken at its guardian stone, wholly in the player's own game: the stone offers it when its stand holds the trophy, and the power is kept in the character, which the server never sees. So no server can take a power away again; what it can do is decide what each player's game knows about the stone. With this on, a player who has not beaten that boss themselves -- read from their raid list the same way as the night spawn guard, with the same drops counting -- is sent the stone without its trophy: to them it is an empty stone that offers nothing. Everyone else sees it as it is, and once a player gets that far their game gets the trophy too, within a few seconds.

  • Only players who may use a stone can hang its trophy. The others' game would offer to hang one from their inventory on what looks like an empty stand, which first asks the stone's owner for the stone. The server refuses that request, whether it owns the stone itself or a player's game does (it does not pass it on to that game, which would grant it), and a stone a player's game took over goes back to the server after 10 seconds.
  • The trophies stay where they are. The server never changes the stone; each player's copy is made as it is sent. Should a game ever send back a stone it was shown empty, the server keeps its own, takes the stone back and logs it. The game's guardian stones set no world key and their trophies cannot be taken down (both read from its data), so a stone shown empty changes nothing else.
  • A player's game gets the stones only once their raid list has arrived, so a veteran logging in at the temple never sees them empty first.
  • When someone hangs the very first trophy on a stone, players who may not use it see it for up to 4 seconds before their copy shows the stone empty again (the stand's own broadcast of the new trophy). Trophies cannot be taken down, so this happens once per stone.
  • A player standing at a stone they may not use is told why (Message), at most once a quarter of an hour per stone.
  • Fader leaves nothing of his own in the raid list; his stone counts as the Queen's.
  • Admins see every stone as it is (ExemptAdmins). A power a character took before this was switched on stays with it.

Portal lock

Valheim pairs portals by their name alone: any two unconnected portals with the same name are connected (Game.ConnectPortals, on the server, every five seconds), and a player who steps into a connected portal is teleported by their own game, which the server cannot stop. So anyone who builds a portal with the name of someone's unpaired one walks into that base -- an untagged portal pairs with any other untagged one -- and anyone who finds a paired portal can use it. What the server does decide is what each player's game is told about a portal, and the lock uses that.

A pair of portals is one thing, and the same player may use both ends (one let through one end must be able to come back through the other):

  • Where a ward holds an end -- the ward (PrivateArea) covers it in its own radius (32 m for the game's ward, the circle seen around it; ExtraReach widens it) and has the portal's builder on its list -- the owner and the players on that list may use the pair. One ward at one end decides for the pair, the far end included, wherever it stands; with a ward at both ends a player has to be on both lists. The ward's own list is used (its owner presses E on it, as before) and it counts whether the ward is switched on or off, so adding a friend never opens the portals. A ward put up over someone's portal later, which does not have its builder on its list, holds nothing.
  • Where no ward holds either end, the builders of the two ends.
  • Everyone, if the name starts with PublicPrefix (*) at both ends; inside someone else's ward only if that ward's owner built the portal. A name can still only be changed by those who may use the pair otherwise.
  • Admins (ExemptAdmins). A portal nobody has built (spawned by an admin, no ward) stays open.

How it is kept:

  • A player who may not use a pair is sent the portal's data with the connection set to "none" (ZDOMan.SendZDOs), and put back right after: to their game the portal is unconnected and does not teleport. Nothing is saved or changed on the server. A client only takes data newer than its copy, so when who may use a pair changes -- a name on a ward, a portal built, a ward moved -- the portal's data revision is raised once and the right copy goes out to everyone within a couple of seconds.
  • Pairing: two unconnected portals of one name are connected only if both builders may use the pair -- with a ward holding an end, each builder is on its list; with none, the same player built both. Two names alike are no consent. Otherwise they stay unconnected and the builder, standing at the portal, is told why. Pairs that exist are not touched, and where no ward holds either end they stay usable by the builders of both; where a ward holds an end, its list decides who may use the pair from then on, so a builder who was never written on it asks the ward's owner (the player is told at the portal).
  • A portal's name can be changed only by those who may use the pair (not by everyone just because it is public). The request is not passed on to the game that owns the portal, data from anyone else is not taken, and a player who may not use a portal is never given it.
  • Everything the game's own wards already do stays: a portal can be taken apart by whoever may take apart pieces in that ward, and nobody else in a ward's area.

What it does not do: it cannot stop a game that has been modified, and it does not hide where a portal stands. A player's character is what counts, not the account: a second character is another player.

Location icons

Some locations carry an icon for the map: the traders (Haldor, Hildir, the Bog Witch), Hildir's three dungeons, the Deep North boss room and the ancient upgrade station; the start temple's is always shown. Vanilla sends every player the icon of each of them as soon as the location is placed -- when its zone is generated, which happens whenever anyone passes within a few zones, usually without anyone seeing it -- and the map draws it whether the player has explored there or not (ZoneSystem.SendLocationIcons goes to everyone; Minimap checks no fog for it). So the first player to pass near Haldor's camp gives everyone his position.

With [LocationIcons] Enabled, the server sends each player only the icons of the locations they have been within DiscoverRadius (50 m) of themselves, also from inside a dungeon above or below, and remembers them per character (<world>.icons.txt, one line per character and location). A player who finds one gets its icon within two seconds. Icons the game always shows stay for everyone, and players' own pins are not touched. Tested with two simulated players on a copy of the live world: far away both were sent only the start temple; the one taken to the ancient upgrade station got its icon too, the other did not; after a restart the first one got both icons at once.

Fire control

How fire spreads, from the game's own code and data (Valheim 1.0.16). Outside the Ashlands all of it needs the Fire world modifier (-setkey fire); in the Ashlands fire always works. Two ways a fire starts, both only from something lit:

  • Sparks. A bonfire or campfire throws one every 5 s (50 % chance each time), a fire burning on a piece every 2 s and one on the ground every 5 s (30 %), in a random upward-biased direction, under gravity alone. On a burnable piece that is not wet, a tree or a log a spark always starts a fire; on uncleared grass, outside the Mountains and Deep North and not in rain, with a 32 % chance.
  • Direct ignition. A lit fireplace sets alight whatever burnable is inside a small capsule around its flame, every 5 to 10 seconds.

Every fire carries a generation count: it throws sparks only while the count is above 0, and what its sparks light gets one less. What a fireplace lights directly gets the fireplace's own count. How far each source reaches -- spark landing distances simulated with the game's own spark code, 400 000 sparks each, on flat ground:

Source Sets alight directly Its own sparks land at most Spark flights the chain can make Farthest on flat ground
Bonfire 1.7 m around, up to 6.2 m above 2.9 m (half within 2.3 m) 4 about 17 m
Campfire 0.45 m, up to 1.6 m high 1.0 m 2 about 8 m
Hearth 1.4 m along the world's east-west axis, 0.8 m across, up to 1.7 m high (the capsule does not turn with the hearth) -- 4 about 17 m
Iron fire pit 0.7 m -- 4 about 16 m
Floor and ceiling braziers 0.3 m; a floor brazier reaches the floor under it -- 1 about 4 m
Standing torches (iron, wood, blue, green) 0.1 m around the flame -- 1 about 4 m
Resin candle 0.1 m, 0.25 % every 25 s -- 1 about 4 m
Sconce, lanterns, jack-o-turnip, snow lantern, NPC fire pits, forges, kilns, smelters never -- -- --
Fire arrow -- 3 sparks on impact, 2.9 m 4 about 15 m
Staff of Embers fireball -- 6 sparks on impact, 5.0 m 4 about 17 m

A fire's sparks fly at 5 m/s and land up to 3.9 m away on flat ground, farther from a height: 5.1 m from a fire 2 m up, 6.2 m from 4 m, 7.8 m from 8 m, 9.1 m from 12 m. "Farthest" adds up the longest flight of every generation, so it is a ceiling: each one has to land on something burnable, in the right direction, before its fire goes out. Ashlands meteors and the summoned troll throw sparks too.

A fire burns for at most 30 seconds (the game's own timer on every fire), and a spark that has not landed within 3 s is gone; in its 30 seconds a fire on a piece throws about four or five sparks, one on the ground about two. It goes out sooner when rain falls on it with no roof above, when what it burns on is destroyed, when a smoke bomb goes off within 3 m, or when it chokes on smoke: under a roof, more than 7 puffs within 2.9 m of a point 3.2 m above it. In a house that is the smoke of a hearth or fire pit; a fire's own smoke source stops puffing as soon as its smoke has nowhere to go -- every smoke source counts itself blocked with smoke within 0.75 m of it (0.4 m for braziers), and a fireplace whose smoke source has been blocked for 4 s goes out until the air clears (see [Fixes] ServerSmoke).

On a dedicated server the weather that puts fires out, and makes pieces too wet to catch, is the Meadows' wherever the fire is: the server has no camera to follow, so the game falls back to the Meadows for it, in the Ashlands and the Swamp as much as anywhere.

Vanilla has no limit in metres; [FireControl] adds one. Every spark and fire remembers the source its chain began at (a lit fireplace, or where an arrow, fireball or meteor came down; kept in its ZDO, so it survives a restart), and with MaxRadius set, a fire that would start farther than that from its source does not start. MaxSpread caps every generation count. FireplaceIgnition = false stops direct ignition entirely: a hearth, brazier or torch then cannot start a fire at all, while a bonfire or campfire still throws sparks.

OnlyProjectiles = true goes further: only a projectile starts a fire. Every spark and fire also remembers whether its chain began at a projectile (in its ZDO), and only those throw sparks; no fireplace sets anything alight or throws a spark of its own. Which attacks carry fire was read from the game's data: a fire arrow (3 sparks where it lands), a Staff of Embers fireball (6), Ashlands meteors and lava rocks, and the sparks of the Ashlands sky. The fireballs of surtlings, fuling shamans and the Charred mages, and Fader's fire breath and wall of fire, deal fire damage but never set anything alight in the game.

Who simulates a fire. Sparks fly, and fireplaces ignite, only on the machine that owns the object, and the server only takes over what nobody owns or what its owner has left. What a player builds or sets alight is created and owned by their own game: without more, a hearth a player has just built, or the fire their arrow started, would burn by the game's rules on that player's computer until they left the area or the server restarted -- in 1.13 and 1.14 none of the settings above reached them. Now the server takes every fire source (every fire, and every fireplace that ignites or throws sparks: 15 kinds) the moment a player's game reports it, whether new, an update from a game that has not heard the news yet, or a fireplace a player merely claimed (pressing E on one nobody owns). That game stops simulating it long before its first spark (2-5 s) or direct ignition (5 s). A fire taken over this way that has no record of its chain was lit by a projectile on that player's computer and counts as one, its own position as the source -- up to 2.9 m from where an arrow, 5.0 m from where a fireball came down, which MaxRadius therefore allows on top. A fire that appears within 8 m of a creature that throws sparks (the summoned troll) is not from a projectile, and with OnlyProjectiles it is put out. The server's copy of a fire finds the piece, tree or log it burns on, so it goes out when that is gone, as on the game that lit it. What stays on the player's computer is their own arrow or fireball and the sparks it throws where it lands.

Hosting notes

  • After a game update, look for Vanilla ... changed warnings in the log, and keep world backups.
  • On a shared host with a chiplet CPU (AMD EPYC, Ryzen), CpuAffinity = auto keeps the server on one die, the one least busy when it starts; other servers on the host are not pinned and may still use it. Each server measures for itself, so two started in the same second can pick the same die.
  • Running under AMP (CubeCoders)? Settings and pitfalls (Sleep mode, stop without save, console commands) are in MistrCech/amp-valheim-bepinex.

Caveats

  • Only runs on dedicated servers.
  • Uses considerably more server resources than vanilla; a weak CPU or little RAM may make play worse, not better.
  • Disable the mod when using the optterrain command.
  • It does not prevent cheating or any kind of client manipulation.
  • Game updates can break it in unexpected ways; back up characters and worlds before updating.

How it works

Ordinarily, to keep server resource usage low, the Valheim server hands off simulation of an area to the first client that enters it. This mod makes terrain, monsters and other objects that are normally created and owned by clients be created on — and thus owned and simulated by — the server, around every connected player.

For mod developers - compatibility

This mod keeps the plugin GUID of Serverside Simulations, MVP.Valheim_Serverside_Simulations, so existing checks for it keep working.

If your mod changes the simulation or behaviour of the world, it has to be able to run on the dedicated server:

  • Player.m_localPlayer is always null on a dedicated server; check for it.
  • On a dedicated server, ZNet.instance.GetReferencePosition() returns a position outside of the world, unrelated to any player.
  • Graphics or HUD code should be behind a ZNet.instance.IsDedicated() check if it can run on the server.

Credits

  • Serverside Simulations by ddormer and its contributors: this is a fork, and the simulation itself -- the zones around players loaded and simulated on the server, the configuration and the feature framework -- is their work. The original is at ddormer/valheim-serverside and on Thunderstore as mvp/Serverside_Simulations.
  • @mreastman: the port to Valheim 1.0 (ddormer/valheim-serverside#118) this fork builds on.
  • @Merl: found why the frame rate patch broke on Valheim 1.0.14 (#1); the refresh rate idea is in 1.11.0.
  • BetterNetworking: the server-side network limits are its idea.

License

Our own work is MIT, see LICENSE. A few files carry code from Serverside Simulations by ddormer, which has no licence; that code is not covered, see NOTICE.md.

Building

Create src/Environment.props pointing at a Valheim dedicated server install that has BepInEx:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <!-- Needs to be your path to the base Valheim dedicated server folder -->
    <VALHEIM_DEDI_INSTALL>E:\SteamLibrary\steamapps\common\Valheim dedicated server</VALHEIM_DEDI_INSTALL>
  </PropertyGroup>
</Project>

Then, from the repository root (Windows or Linux, tested with .NET SDK 10):

dotnet build src/Valheim_Serverside/Serverside_Simulations.csproj -c Release -p:SolutionDir=<repository root>/

The DLL ends up in bin/Release/. SolutionDir is needed when building the project on its own; building Valheim_Serverside.sln sets it.

CHANGELOG

[1.18.3] - 2026-10-12

Changed

  • Thunderstore package only (Sarkastic_gg/Dedicated_Simulation): LICENSE (MIT, for the work of MistrCech / Sarkastic.gg) and NOTICE.md (what it does not cover: the parts that come from Serverside Simulations, which has no licence, and third-party components) are in the repository and in the package; the README says so. The plugin is the 1.18.0 DLL, unchanged.

[1.18.2] - 2026-10-12

Changed

  • Thunderstore package only (Sarkastic_gg/Dedicated_Simulation): the README has badges and links (Discord, Patreon) and the package is listed in the "Deep North Update" section. The plugin is the 1.18.0 DLL, unchanged.

[1.18.1] - 2026-10-12

Changed

  • Thunderstore package only (Sarkastic_gg/Dedicated_Simulation): an icon of its own, and the README's credits and companion plugin. The plugin is the 1.18.0 DLL, unchanged; a package's icon can only change with a new version number.

[1.18.0] - 2026-10-11

Added

  • [PortalLock] (off by default): a pair of portals is used only by those it belongs to. Valheim pairs portals by name alone and a connected portal teleports whoever steps into it, so a portal built with the name of someone's unpaired one walks into that base. Now the builders may use the pair, and where a ward holds an end (covers it and has the builder on its list) the owner and the players on that list instead -- one ward at one end decides for the pair, the far end included; wards at both ends: a player has to be on both lists. A name starting with PublicPrefix (*) is open to everyone. A player who may not use a pair is sent the portal unconnected (the connection is left out of that one copy; nothing is changed on the server); two portals of one name are paired only if both builders may use the pair (without a ward: the same player built both); a name is changed only by those who may use the pair; pairs that exist are not touched (usable by both builders where no ward holds either end). A ward holds an end only with the portal's builder on its list, so a ward put up over someone's portal afterwards takes nothing. Messages at the portal tell the player why. Tested on a copy of the world with four simulated players: the same scenario with the lock off shows vanilla (every player is sent every pair, a stranger renames a portal and takes it over, portals with nobody in common pair), with it on only the intended players get each pair, a stranger's rename and forged data are refused, a name written on a ward's list and taken off it again reach the players within seconds. The ward's radius is the game's own, 32 m for guard_stone. On a copy of the live world (11. 10.) there are 4 portals, one pair, all built by one player: nothing that exists changes.

[1.17.0] - 2026-10-11

Added

  • [CharacterGuard] Welcome (off by default), WelcomeTitle, WelcomeLines: a character let in for the first time is greeted a few seconds after joining -- the title in the middle of the screen, then each line in the top left corner (the vanilla ShowMessage RPC, nothing to install). A kicked character gets its kick message instead.

Fixed

  • [CharacterGuard] ChangedAway flagged a new player who picked up a club in the minute before a restart (live, 10. 10.): what a character wears was noted every minute and when it left, but a server shutdown never disconnects anyone, so a change in the last minute looked like play elsewhere. It is now noted at every world save and at shutdown too, and only gear past a level 1 workbench counts as a change -- a club or rags are made anywhere in minutes. Tested on a copy of the world with four simulated players, against 1.16.0 as the control: a bronze sword put on 5 s before quitting and a club are no longer flagged (1.16.0 flagged both), an iron sword never worn here still is.

[1.16.0] - 2026-10-10

Added

  • [LocationIcons] (off by default): a location's map icon -- Haldor, Hildir, the Bog Witch, Hildir's dungeons, the Deep North boss room, the ancient upgrade station -- only for players who have been within DiscoverRadius (50 m) of it themselves. Vanilla sends every player every such icon as soon as the location is placed, which happens when anyone passes within a few zones of it, and the map shows it whatever the player has explored: the first player near Haldor's camp gives everyone his position. ZoneSystem.SendLocationIcons is replaced by a per-player version (also when a player joins and when a location is placed); found icons are remembered per character in <world>.icons.txt and sent within two seconds of finding one. The start temple's icon (always shown by the game) stays for everyone. Tested with two simulated players on a copy of the live world, including a restart.

[1.15.0] - 2026-10-09

Added

  • [Server] CpuAffinity (empty by default: as before): auto pins the server to one chiplet -- on AMD EPYC and Ryzen a die with its own L3 cache, on the first EPYC generation also with its own memory -- the one least busy over one second at startup (measured on a background thread, so startup does not wait), read from the system's own topology: Windows processor dies (GetLogicalProcessorInformationEx), else NUMA nodes, else L3 groups; Linux /sys die, node and cache lists. Only processors the process may already use are considered. Or a list such as 16-31. Windows sets the whole process (SetProcessAffinityMask: no thread can leave it); Linux every thread, read again until no new one appears, and once more 30 s and 5 min after startup for threads that set their own processors (Steam starts three). If anything is unclear -- one chiplet, load unknown, a list that is not one -- nothing changes and the log says why.
  • [Server] ProcessPriority: Normal (as before), AboveNormal or High (Linux: nice -5 / -10).
  • [FireControl] OnlyProjectiles (off): only a projectile starts a fire -- a fire arrow, a Staff of Embers fireball, a meteor, a lava rock -- and what it sets alight burns and spreads as before (within MaxRadius and MaxSpread); nothing a base has (fireplaces, the fires they lit, the troll a player summons) throws a spark or sets anything alight. Every spark and fire records whether its chain began at a projectile (sgg_fire_kind in its ZDO). From the game's data: surtlings', fuling shamans' and the Charred mages' fireballs never set anything alight.

Fixed

  • Fire control reached only the fires and fireplaces the server simulated. What a player builds or sets alight is created and owned by their own game, and the server only takes over what nobody owns or what its owner has left, so a hearth a player had just built, or the fire their arrow started, burned by the game's own rules on that player's computer until they left or the server restarted -- since 1.13.0. The server now takes every fire source (every fire, and every fireplace that ignites or throws sparks) the moment a player's game names itself its owner: a new one, an update from a game that has not heard yet, or a bare claim with no data (Fireplace.Interact on an ownerless fireplace, which never reaches ZDO.Deserialize) -- noted in ZDO.SetOwnerInternal while ZDOMan.RPC_ZDOData runs, taken when it is done. A fire taken over without a record of its chain counts as from a projectile, rooted at its own position, unless a creature that throws sparks (the summoned troll) is within 8 m; with OnlyProjectiles such a fire is put out. The server's copy of a fire finds the piece, tree or log it burns on, so it goes out when that is gone.

An independent review by two readers found that a bare ownership claim was missed, that a fire taken over lost the piece it burned on, that fires of the summoned troll counted as from a projectile, and, in the processor placement, that an unknown load picked a chiplet blindly, that offline Linux processors broke the die reading, that a priority failure could stop the plugin loading, and that malformed lists were read leniently; all fixed above. A player's own arrow or fireball still throws its first sparks on their computer, so MaxRadius counts from the first fire it lit (up to 2.9 m from an arrow's impact, 5.0 m from a fireball's).

Tested on 1.0.16: with OnlyProjectiles a lit bonfire, hearth and floor brazier on a wood deck and two loose fires set nothing alight in 60 s, while a Staff of Embers burst (6 sparks, recorded as projectile) lit the grass twice and those fires threw sparks on. A simulated player's game reported a lit hearth, a fire and a fire arrow: the server took the hearth and the fire at once (the fire as from a projectile) and left the arrow; a newer update naming the player's game the owner, and a bare claim, were both taken back the same moment, with the owner change sent back. A fire reported 2 m from a summoned troll was put out; one on a wood floor found the floor and went out when the floor was destroyed. Processor placement on a Ryzen 9 7900X3D: auto read 2 dies and took the idler one (processors 0-5,12-17); the three threads Steam starts a few seconds later with all processors were moved back after 30 s, leaving all 88 threads on the die. On the live host (Windows 11, EPYC 7551P), a standalone probe with the same code, pinning only itself, read 4 processor dies (0-15, 16-31, 32-47, 48-63), the same 4 NUMA nodes and 8 L3 groups, measured all 64 processors and took die 0-15, 5 % busy; malformed lists were refused with the reason.

[1.14.0] - 2026-10-09

Added

  • [GuardianStones] (off by default): a boss's trophy on its guardian stone, and so its power, only for players who have beaten that boss themselves. A power is taken and kept wholly in the player's own game, so a server can never take one back; instead each player's game is sent the stone as that player may use it: a stone whose boss they have not beaten arrives without its trophy (s_item set to 0 in the stone's own data for that one serialization in ZDOMan.SendZDOs, and put back -- no revision change, nothing saved), and their vanilla client has no power to offer. Their game would offer to hang a trophy of their own on what looks empty, which first asks the stone's owner for it: refused where it reaches the server, whether the server owns the stone (ItemStand.RPC_RequestOwn) or a player's game does (the request is not passed on, ZRoutedRpc.RouteRPC -- that game would grant it); also refused while their game may still hold an empty copy. A stone a player's game took over goes back to the server after 10 s. Data for a stone from a player who was sent it empty is not taken (ZDO.Deserialize skipped, the server takes the stone back and raises its revision). Once a player gets that far, the stone's revision is raised once (while the server owns it), and their game takes the trophy; an empty copy counts as theirs until a newer revision has gone out. No stone is sent to a player until their raid list has arrived (ZDOMan.CreateSyncList), so a veteran logging in at the temple is never sent them empty first. A player standing at such a stone, or refused one, is told why (Message). Progress is read as for the night spawn guard (now shared, Progress). The game's guardian stones set no world key and their trophies cannot be taken down (read from its data). A review by three independent readers found that a stone owned by another player's game let the request through to that game, that dropping the bookkeeping when the same revision went out left a player's game with a stale empty copy, and that a veteran logging in got the stones empty first; all three are fixed above. Tested on a 1.0.16 copy of the live world, all seven stones with their trophies, reading back what each simulated player's connection was actually sent: a fresh player got every stone empty, a veteran all seven trophies, a player past the Elder only Eikthyr's and the Elder's; the fresh player was refused the Eikthyr stand, the veteran given it; with the veteran's game owning Yagluth's stone, the fresh player's request for it was not passed on (the veteran's connection never got it) and the stone was the server's again 10 s later; data sending Bonemass's stone back empty was not taken; the fresh player at Eikthyr's stone was told; a request from the fresh player in the moment their list said past the Queen, while their game still held the empty copy, was refused; then all seven stones went out to them with the trophies; a player whose list had not arrived got no stone at all until it did, then all seven with the trophies; every trophy in place at the end; patch, transpiler and raid checks pass; no exceptions from the plugin.

Changed

  • The night spawn guard's README now says which drops count for each boss, read from the game's drop tables: for Yagluth only a Torn Spirit (or a Wisp or Demister), for the Queen only a Majestic Carapace, not their trophies; "passing the trophy around" was right only for the first four bosses.

[1.13.0] - 2026-10-09

Added

  • [NightSpawnGuard] Enabled (off by default): the spawns that come with boss progress -- Greydwarfs at night after Eikthyr; Draugr, Greydwarf Elites and Shamans and Odin after the Elder; Skeletons after Bonemass (the Menhir alt biome's too); Goblins after Yagluth; Seekers, Seeker Brood and Ticks after the Queen; Charred after Fader, read from the game's own spawn tables -- are held back in a spawn zone until every player in it has got that far themselves. Until then the zone behaves as in a world where that boss still lives (the entry's key is swapped for one no world has, for the one call, and always restored, also when the game's code throws). A player's progress is read from the raids their own client still lists for them (possibleEvents): the first main raid still listed, with the forest troll and surtling raids confirming the Elder's and Bonemass's steps, so a power taken at a stone someone else filled does not count as a kill. Worked out with a port of the game's raid check over its 1.0.16 raid data, for every progress level and every combination of other people's powers (README). Raids are not touched. If the game's raid data stops matching, the guard does nothing and says so. Tested on a 1.0.16 server at midnight with every boss's key set, players in open meadows: a newcomer with a veteran, and a newcomer who took Eikthyr's power from someone else's trophy -- all 13 entries held back; two players past Bonemass -- only Goblins, Seekers, Seeker Brood, Ticks and Charred held back, and a Greydwarf Elite spawned; a player past the Elder holding four other bosses' powers -- held back from Skeletons on; two veterans -- nothing held back; after a minute of it no spawn entry was left with the stand-in key (0 of 2602).
  • [FireControl] (off by default): MaxRadius -- a fire starts only within this many metres of the source its chain began at (a lit fireplace, or where an arrow, fireball or meteor came down; every spark and fire keeps it in its ZDO); MaxSpread -- caps every spark generation count; FireplaceIgnition -- off, no fireplace sets alight what touches its flame, so a hearth, brazier or torch cannot start a fire at all. How far every fire source reaches in the game is in the README, worked out from its code and data: what each fireplace sets alight directly (the hearth about 1.4 m, the bonfire 1.7 m around and 6.2 m up, a floor brazier the floor under it, standing torches 0.1 m; sconces, lanterns, forges, kilns and smelters never), how far a spark lands (simulated with the game's own spark code: bonfire 2.9 m, campfire 1.0 m, a fire 3.9 m on flat ground and farther from a height), and how many generations follow. Tested on a fresh copy of the live world with a lit bonfire on a 14x14 m wooden deck, a hearth 1.3 m from a wooden wall and a floor brazier on wood: with the game's rules the hearth lit the wall three times in 15 s, the brazier the floor under it, and the deck burned outwards to 8.4 m within 25 s of the first spark landing (7 floors gone after 40 s); with MaxRadius = 3 and FireplaceIgnition = false nothing was lit directly, no fire started beyond 3.0 m of its source (5 stopped, 3.1-6.1 m out) and no floor burned; 0 exceptions.

Fixed

  • Fireplaces smothered for everyone but the server ([Fixes] ServerSmoke, on). A smoke source only puffs while the local player is within 64 m; a dedicated server has none, so the server never saw smoke: a fireplace in a room full of smoke -- every smoke source counts itself blocked with smoke within 0.75 m of it (0.4 m for braziers), and a fireplace blocked for 4 s goes out until the air clears -- went out for every player and kept burning on the server, using fuel, throwing sparks and setting what touches it alight; and a fire under a roof never choked. Now a smoke source puffs on the server while any player is within the same 64 m (SmokeSpawner.Spawn, one read of Player.m_localPlayer swapped for the nearest player in range), and the game's cap of 100 puffs at a time is counted once per connected player. Tested: the server made smoke around a player (up to 230 puffs with the test's fires and fireplaces), and a fire's own smoke source in a closed room counted itself blocked once its smoke had nowhere to go, as it does on a player's computer; 0 exceptions. How often that smothers a fireplace or chokes a fire depends on the room; a fire still burns 30 s at most either way.

[1.12.1] - 2026-10-07

Changed

  • Renamed to Sarkastic.gg Dedicated Simulation: the community moved from sarkastic.eu to sarkastic.gg. The DLL is now SarkasticGG_Dedicated_Simulation.dll; delete SarkasticEU_Dedicated_Simulation.dll from BepInEx/plugins when upgrading (BepInEx would load only the newer of the two, but the old file stays behind). The plugin GUID, and so the config file MVP.Valheim_Serverside_Simulations.cfg, is unchanged, and nothing else is.

[1.12.0] - 2026-10-03

Valheim 1.0.16 (Steam build 25527701, 25 September 2026) changes none of the methods this mod patches; 1.11.1 passes the patch, transpiler and raid checks on it, and so does this release.

Added

  • [CharacterGuard] (off by default): a server-side check on the characters players join with, for servers whose players keep vanilla clients. A vanilla client never sends its inventory, so the server cannot read or replace it; it sees the character's id, what it wears (with weapon upgrade levels), and the raids it is ready for, which the game derives from the items it knows and the bosses it has beaten. A character this world has not seen must be fresh -- still ready for Eikthyr's raid and wearing nothing beyond a level 1 workbench -- or it is shown a message and kicked (NewCharacterAction: Kick, Log, Ignore). A known character that comes back wearing something new or ready for other raids than when it left is logged (ChangedAway: Log, Kick, Ignore). Characters that built something or own a bed or tombstone in the world count as known, so existing players are not locked out; admins are exempt. Console: characters, allow <name>. The list is kept in <world>.characters.txt. Tested with fake players on a copy of a live world: a fresh character and one with a club and rags let in, one with iron gear and progress kicked, a builder of the world let in; on their return a new sword and new raid readiness logged (or kicked with ChangedAway = Kick), an unchanged character let in, and allow both cancelling a pending kick and letting a kicked character in.
  • [ItemLedger] Mode (Off by default; LogOnly; On): an account per character of the items that lock progress, for servers whose players keep vanilla clients: what it got on the server and what it put back into the world. In: picked up (a DestroyZDO from that player), taken out of a container or off a stand. Out: dropped -- only what has been in a bag, which the game marks, so the resources of a removed piece do not count, and what falls out of a chest or stand its owner removed is matched against what it held -- put into a container or on a stand, fed to a smelter, cooking station or fermenter, offered at a boss altar, built with, died carrying. What a character wears and holds is checked every 10 seconds; an upgrade shows as a higher quality. More out than in, and than it could have crafted, came from another world: written to <world>.guard.log, and with On taken away -- a dropped stack cut down, a container or stand emptied of it once nobody uses it, a smelter's queue undone, a boss altar refusing -- and the player told (Message, AltarMessage). Only exact accounts are acted on: a new, fresh character from zero, any other after its first death here, when the tombstone shows the whole bag; for the first GraceHours (168) no character counts as new. Admins are exempt. Accounts in <world>.items.txt. Findings for an account that is not exact yet go to the guard log only, not to the BepInEx log.
  • Both features keep out of the game's way: every patch catches its own faults and logs them (at most 20 in a quarter of an hour), so a fault never stops the original method -- a disconnect, a boss summon, object data from a player. If the accounts or the known characters cannot be read, that feature stays off until the next start and leaves the file as it is; a save cut short is read back from its .tmp. Container contents are read without creating the items, as Inventory.Load would for every stack. The guard notes what an online character wears and knows every minute, since a server shutdown does not disconnect the players one by one.
  • [ItemLedger] Items = auto: the items that lock progress, from the game's own data -- what cannot go through a portal, what bosses drop and what summons them, every material that all recipes and pieces using it need more than a level 1 workbench for, every item that all its recipes need more for. 544 items in Valheim 1.0.16, listed by reason in the guard log at startup; ExtraItems and ExcludeItems adjust it, and what traders sell is always left out.
  • Crafting is not seen, so a tracked item counts as crafted from the tracked items the character got, reckoned in its favour wherever the game leaves room: the crafting bonus at its luckiest (three more per craft at a station, for a lucky batch of five), an upgrade made at the 1.0 upgrade station with upgrader items, an item broken there handing back 35 % of its materials (never one it wears), a caught fish bringing the most its extra drops can (a Fish10 one silver, a Fish6 two iron ore). A recipe is paid in full or not at all, and an item the game removes after an hour with nobody near is no pickup.
  • Tested on a copy of a live world on Valheim 1.0.16, with simulated vanilla clients sending through the server's own network entry points (ZDOMan.RPC_ZDOData, routed calls): black metal put into a chest, iron dropped, iron scrap and copper ore fed to a smelter, a boss trophy put on a stand, silver beyond what one caught fish brings and copper the game had removed 37 m away put into a chest, a boss summoned with blood the character never got -- logged, and with On taken out of the chest, cut, dropped from the smelter's queue, taken off the stand, refused by the altar. Bronze dropped beyond the four bars its copper and tin could make with the best luck: the one bar over logged, and only logged when the drop was picked up again at once. Nothing logged for a chest a player removed or a trophy taken off a stand, picked up again; a caught fish's silver; bronze from a sword broken at the upgrade station once it was no longer worn. Its upgrade while worn was reported as the cheaper of the two ways, one upgrader item. An older character's silver noted as unverified until its death, then 2 beyond what it took back taken away; a forge built from copper it never got only logged.
  • The character guard and the item ledger write their own log, <world>.guard.log.

Fixed

  • The console help said setkey and removekey need devcommands; they do not (only listkeys, resetkeys and the like are cheats).

[1.11.1] - 2026-09-25

An audit of every patch against Valheim 1.0.15 and 1.0.12, prompted by MistrCech/valheim-serverside#2. That pull request's premise does not hold -- the only public build, 1.0.15 (25390671, 18 September 2026), still calls IsAnyPlayerInEventArea in RandEventSystem.FixedUpdate, and raids go active on it with this mod -- but the patch was fragile in the way it describes.

Fixed

  • Random events: the RandEventSystem.FixedUpdate patch finds the three sites it needs by the field and method each uses and changes the method completely or not at all, with a warning naming what is missing. Before, if a game update moved the call it reuses, it did nothing without a word -- or reversed the local player check without replacing the local player's position, which would throw on every fixed step of an event. Checked by blanking each site in the real IL: 1.11.0 reversed the check alone in two of three cases, 1.11.1 left the method unchanged and warned in all three. The same for SpawnSystem.UpdateSpawning, whose patch threw instead and so switched off the whole mod.
  • Players still logging in (version check, password) no longer count as players standing at the world origin. Every per-player loop counted them, so while someone sat at the password prompt the server loaded the zones around the origin and simulated what is there. Measured with a player who never finishes logging in: 1.11.0 loaded the origin zone and 9 objects around it, 1.11.1 nothing.
  • Ship.UpdateOwner checks that the ship still has its network object, as vanilla does: the timer can fire in the frame the ship is removed.
  • Event spawners check the player against the active event, the one whose spawners they get, instead of the random event.
  • ValheimPlus compatibility is patched outside the per-feature safety net, so a ValheimPlus version its patches do not fit threw out of startup and left the whole mod unpatched. It is now logged and the rest applies.
  • [Fixes] DungeonLoadGuard runs after ValheimCommunityPatch's own fix for failed dungeon rooms, as its description always said; before, that depended on the plugins' load order.

Changed

  • [MaxObjectsPerFrame] MaxObjects accepts 1 to 10000 (0 or less throttled creation to about one object per frame), and its description says what a vanilla dedicated server does: 100.
  • The vanilla drift check also watches ZNetScene.OutsideActiveArea and is reviewed for 1.0.15.

Removed

  • The WearNTear.UpdateSupport prefix. It called SetupColliders when m_colliders was set and m_bounds was not, but the game only ever sets both together, so it never did anything -- on every building piece's support update.

[1.11.0] - 2026-09-23

Added

  • [Fixes] DungeonLoadGuard (on): a dungeon whose room bundle Unity refuses to load no longer wedges its zone. In the game's asset loader a refused bundle ("another AssetBundle with the same files is already loaded") is stored as null and still reported as loaded; the next step throws, the dungeon never hears back, never spawns, and its zone stays flagged as loading -- on a server seen as an endless loop over the same dungeons (ddormer/valheim-serverside#120). Only a server running this mod gets there, since a vanilla dedicated server never loads dungeons. The guard takes over the bundle Unity already holds, reports a load that really failed as failed instead of throwing, and lets a dungeon with a failed room go so its zone keeps working and it is tried again the next time it is created. Checked by opening the forest crypt room bundles behind the loader's back: 1.10.2 logged 13 refusals, threw, and spawned none of three crypts; 1.11.0 took over all 13 bundles and spawned all three.

  • Compatibility with ValheimCommunityPatch, which speeds up the object pass around one point, the server's reference position -- the world origin on a dedicated server -- while this mod simulates around every player:

    • its zone-diff unload (ZNetScene.RemoveObjects) drops everything outside the simulation distance of that point whenever the object lists look as the game filled them, which they do when no players' areas overlap. Objects around the players were then destroyed and created again on every pass: doors, beds and items that could not be used, dungeons reloading dozens of times a second until Unity refused their room bundles as already loaded, once a crash of the server itself (ddormer/valheim-serverside#119, #120). Measured with two players walking between two dungeons: 178 to 1903 dungeon loads at up to 90 a second and hundreds of refused bundles with it, 52 loads and none without it;
    • its spawn queue (ZNetScene.CreateObjectsSorted) orders new objects by distance from that point, so this mod's ordering by the nearest player never ran.

    Neither has a switch of its own; both are removed when the world starts unless [Compat] ValheimCommunityPatchUnload / ValheimCommunityPatchSpawnQueue keeps them, the rest of ValheimCommunityPatch is left alone. With the unload kept, the object lists are marked as edited on every pass so it takes the game's own unload check, its own path for mods like this one (measured: 52 loads, no errors).

Changed

  • The frame rate patch also sets the refresh rate the game assumes (1.0.14 and later), so 30 and 60 FPS no longer depend on what display modes a headless process reports. Idea from @Merl in MistrCech/valheim-serverside#1.

[1.10.2] - 2026-09-21

Fixed

  • Valheim 1.0.14 gave PresentManager.RequestTargetFrameRate a second parameter and renamed the first (the patch that let the frame rate limiter work with v-sync), so the patch that sets the server's frame rate failed and took the whole Performance feature down with it (logged as "Feature Performance failed to apply and is disabled"). From 1.0.14 on, the server therefore ran at the game's 30 FPS, without the even world-update interval, the physics catch-up limit, the zone budget and the performance report. The patch now takes every overload of that method and its first argument by position, not by name. Reported by @Merl in MistrCech/valheim-serverside#1, who found it first and also traced it to 1.0.14.

    Checked on 1.0.15 against 1.0.12 with a server simulating a base: a client's UseDoor toggles the door, a bed takes its owner, an item a client claims stays claimed, and army_eikthyr spawns its waves -- the same on both versions.

[1.10.1] - 2026-09-13

Fixed

  • Accented letters typed into the server console arrived as ?: AMP on Windows writes its own code page to the process while Unity's Mono reads standard input as UTF-8. Lines are now read as bytes; valid UTF-8 is taken as such, anything else is decoded with [Server] ConsoleInputCodePage (1250 by default; 852, 1252, 65001), and the first such line is logged with its bytes so the right page can be set.

[1.10.0] - 2026-09-13

Added

  • Console commands broadcast <text> (a message in the middle of every player's screen, the way the game announces a raid) and event <name> <player> (a raid at that player; events lists the names). The game's own event needs a local player and cannot work on a dedicated server.
  • Anything typed on the server console that is not one of ours is passed to the game's own console, which a dedicated server has but never reads, and what it prints goes to standard output for the panel. So the vanilla server commands work too: kick, ban, unban, banned, stopevent, randomevent, and after devcommands the cheat commands that need no player: skiptime, setkey, removekey, resetkeys, listkeys, env, tod, wind. Verified on a local 1.0.12 server.

Fixed

  • [Fixes] TeleportGhosts: a player who portalled or respawned stayed visible to the players near the old spot, frozen, until they next crossed a zone line. Valheim 1.0 files an object under its new sector before it stores the new position, and the check that tells each player to drop objects that left their area reads the position, so it saw the old spot and queued nothing. The check is re-run once the position is stored; a player already told has no entry left, so nothing is sent twice. Reproduced and verified with a fake peer on a local 1.0.12 server. Reported for 1.0 by ValheimCommunityPatch ("Fix Teleport Ghost Players").

Removed

  • [AdminChat]: a Valheim client runs anything typed into the chat with a leading / as a local console command and never sends it, so /give could not reach the server from a real client. MaxGiveAmount moved to [Server].

[1.9.0] - 2026-09-12

Fixed

  • [Fixes] SaveClientChanges: Valheim 1.0 saves only the world chunks it marked as changed, and a change that arrives from a player for an object the player owns marks nothing, so the new state lived only in memory until something else in that chunk changed. The chunk is now marked when such a change arrives. With this mod the server owns nearly everything near players, so the window was small: what a player just built, the ship they steer, their drops. Reported for 1.0 by ValheimCommunityPatch.

[1.8.0] - 2026-09-11

Added

  • Console replies are also written to standard output, so a panel such as AMP shows them even with BepInEx's console off.
  • Console commands give <item> <amount> <player> (drops the items in front of that player, stacked as the item allows; the name may be a unique beginning) and players, next to save and stop, for the panel the server runs in. Valheim 1.0 only lets the host use cheat commands, so spawn from the game console says "not valid in the current context" on a dedicated server even for admins.
  • [AdminChat] (off by default): admins listed in adminlist.txt can shout /give <item> [amount], /save and /help; replies go to their console.
  • The performance log now says what the slowest frame of each period was doing: players' messages, world updates, object creation, zone generation, creature logic, other game updates, saving, and how much was Unity's own work (physics, garbage collection), with the garbage collections that ran in that frame. On the live server a ~300 ms frame showed up almost every 5 minutes without a known cause.

[1.7.0] - 2026-09-11

Added

  • [Performance] ServerTargetFps (60): the game sets a dedicated server to 30 FPS, so a frame finished in 12 ms still lasts 33 ms and every reaction to a player waits for it. Measured on the live server with one player: 30 FPS at a median frame of 35 ms while the game logic took a fraction of that. 60 halves the wait whenever the server has the headroom and changes nothing under load. 0 keeps the game's 30.

[1.6.0] - 2026-09-11

Added

  • [Performance] settings that smooth the server's frame time, and a periodic performance log (StatsIntervalMinutes): FPS, frame time (average, median, 95%, 99%, worst), fixed steps per frame and the share of time their game logic takes, the cost of sending world updates and of generating zones. With this mod the server simulates everything, so its frame time is what players feel: a felled tree turns into wood only after the server has caught up.
  • SendIntervalMs (100): every player gets world updates at a fixed interval, the sends spread over the frames in between. Valheim serves one player per frame, so with N players each waited N+1 frames: at 15 FPS with 4 players about 330 ms, and longer with every player who joins. Measured under load with 4 players: about 3x as many sends for 0.4 percentage points more of the main thread.
  • MaxCatchUpMs (100): after a slow frame Unity reruns the fixed step (physics, every character, creature AI) once per 20 ms missed; Valheim allowed 200 ms of catch-up, i.e. 10 steps after one bad frame, which made the next frame bad too. Now at most 5. Game time runs slightly slow during such frames.
  • MaxZonesPerTick (1): new zones are generated one per zone tick, players taking turns, instead of one per exploring player in the same frame. Measured under load with 4 players exploring: the worst zone tick fell from 70-177 ms to 22-47 ms, with the same number of zones generated per minute. It caps how many zones a tick generates, not what one costs: a zone holding a large location can still take a few hundred ms.

None of these raise the frame rate; they cut the spikes and the waiting between server and player. Measured on a local copy of a live world with four simulated players walking outward and an artificial 50 ms of load per frame plus a 300 ms stall every 10 s.

[1.5.0] - 2026-09-10

Added

  • Console commands on standard input: save saves the world, stop saves and shuts down cleanly. Lets server panels such as AMP stop the server without losing progress since the last autosave (AMP: App.ExitMethod=String, BepInEx console disabled).
  • Cap Unity job worker threads at 8 ([Server] UnityJobWorkers). Unity starts one per CPU core and idle ones still use CPU; an idle server on a 24-thread machine went from 108% to 38% of a core.
  • The server creates the objects nearest to a player first. It sorted them by its own reference position, which on a dedicated server lies outside the world, so after a portal or entering a new area the surroundings of a player could be the last to become active. Idea from upstream PR #100 by jsza.

Changed

  • Default per-player send queue raised from 32 KB to 48 KB. On a live server with four players it was full in about 0.1% of send ticks, only in bursts (portals, new areas), peaking at the 32 KB limit. 48 KB at 20 ticks/s is about 960 KB/s, just under the Steam send rate cap. Existing config files keep their value.

Fixed

  • Generate ghost zones around players again, as vanilla does. The ZoneSystem.Update replacement only created local zones, which reach the near simulation distance, so unexplored land in the far ring was not generated ahead of players and distant objects there (large trees, cliffs, the Mistlands mist) appeared only much closer.

[1.3.0] - 2026-09-10

Added

  • Server-side networking limits from BetterNetworking (by CW-Jesse, MIT): per-player send queue 32 KB instead of 10 KB and Steam send rate 256-1024 KB/s instead of 150 KB/s, configurable under [Networking], with a periodic log of how often each player's send queue was full. Clients stay vanilla.

[1.2.0] - 2026-09-10

Changed

  • Renamed to Sarkastic.eu Dedicated Simulation, a fork of Serverside Simulations by ddormer. The plugin GUID is unchanged; delete Serverside_Simulations.dll when upgrading.
  • Game members are accessed directly instead of through Traverse, so game updates that rename them fail the build instead of silently doing nothing. If a Core patch fails to apply the mod now removes all its patches and the server runs vanilla. A startup check logs a warning when a vanilla method replaced by the mod has changed since it was last reviewed.

Fixed

  • Update for Valheim 1.0 (Vector2s zones and SimulationDistance). Based on ddormer/valheim-serverside#118 by @mreastman, which also fixed item pickup and the Pickable.RPC_Pick null reference.
  • Fix the ZoneSystem.Update replacement dropping vanilla behaviour: location prefabs loaded by the server were never released (a memory leak), zones were created while locations were still being generated, and ZoneSystem.TimeSinceStart stayed at zero.
  • Fix the server never creating objects when started with a non-classic -simulationdistance (any value other than 0 or 2).
  • Fix Valheim 1.0 null references on the server: ship sails changing (repeated every physics frame while the sail moved), taking items from a Frost Foundry (the item was duplicated and stayed in the station) and leviathans diving.
  • Update ValheimPlus compatibility (GetNearbyChests)

[1.1.9] - 2025-05-14

Fixed

  • Fix missing effects (Revert EffectList.Create patch)

[1.1.8] - 2025-04-20

Added

  • Remove AudioMan.Update, reducing future error spam

Fixed

  • Fix null references to WearNTear.m_bounds and Humanoid.m_currentAttack.m_character
  • Fix shield generators and audio log spam

[1.1.7] - 2024-11-12

Added

  • Environment.props and bepinex publicizer

Fixed

  • Update method references to static, fixing Bog Witch launch issue. Thanks to @bpage-dev

[1.1.6] - 2023-11-22

Fixed

  • Fix exception when updating ship owner in 0.217.28
  • Fix MaxObjectsPerFrame transpiler for Valheim 0.217.28

[1.1.5] - 2023-10-25

Fixed

  • Fix private method access errors in Release build

[1.1.4] - 2023-10-24

Changed

  • Mistlands update

Misc

  • Fix AssemblyPublicizer output path.
  • Update BepInEx, Harmony and MonoMod libs

[1.1.4] - 2023-10-24

Changed

  • Mistlands update

[1.1.3] - 2021-09-22

Fixed

  • Fix Valheim Plus autofuel compatibility.

[1.1.2] - 2021-09-16

Changed

  • Remove old fishing fixes (appears to have been fixed in latest Valheim patch)

[1.1.1] - 2021-05-14

Changed

  • Update to BepInEx 5.4.10

Fixed

  • Fix fishing

[1.1.0] - 2021-05-07

Added

  • Added "max objects per frame" configuration. Allowing for faster or slower area loading on the server.

[1.0.3] - 2021-04-21

Fixed

  • Fix Ship container access and improve Ship ownership transfer
  • Fix Ship taking 10 damage when owner changes to server.

[1.0.2] - 2021-04-19

Fixed

  • Fix objects not being created on the server in 0.150.3.

[1.0.1] - 2021-04-15

Fixed

  • Prevent event monsters from spawning outside of the random event area, during a random event.