You are viewing a potentially older version of this package. View all versions.
mage38-Vanilla_Fix-1.9.0 icon

Vanilla Fix

Small fixes for overlooked vanilla quirks: camp fires that burn out before you arrive, fish that trigger item merging, crafting stations that protect only 20 m after loading, and more. Every module can be toggled.

By mage38
Date uploaded 4 days ago
Version 1.9.0
Download link mage38-Vanilla_Fix-1.9.0.zip
Downloads 73
Dependency string mage38-Vanilla_Fix-1.9.0

This mod requires the following mods to function

denikson-BepInExPack_Valheim-5.4.2350 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.2350

README

Vanilla Fix

Small fixes for quirks of vanilla Valheim that rarely get noticed but quietly take something away from the game. Every fix is a separate module and can be switched on or off in the config file.

This mod was written entirely by an AI (Claude, by Anthropic), directed and play-tested by its publisher. Every behaviour it changes was first traced in the game's own code.

What it fixes

In plain words first - the details for modders and the curious are further down, under "Technical details".

On by default

  • Unload After Travel - After a portal trip or a long sea voyage, the textures and models of the place you left are freed from video memory. The game itself only does this when you sleep, die or pause, so a few trips to other biomes can leave it running slower until you restart.
  • Camp Fires - The bonfires and fires of a Fuling camp no longer go out just as you arrive, and fires that had already burnt out are lit again - as long as Fulings still hold the camp. Once you clear the camp, its fires are left to burn down normally.
  • Ground Item Merging - The fish swimming nearby no longer make the items you dropped snap together into stacks. The game merges dropped items once more than 200 of them are loaded, and it counts every fish in the sea as one.
  • Station Range - Workbenches, forges and artisan tables keep monsters from spawning across their full range as soon as they load. In the vanilla game they protect only 20 m until you walk up to them, so monsters can appear inside your base right after you arrive.
  • Tomb Exit - The exit of the Smouldering Tomb (Hildir's quest) works from inside again. Normally its "Exit" prompt only flickers up at the very edge of the opening.
  • Fire Warmth - The fire icon, and its warmth, no longer follows you around after you leave a fire. It happens when rain dampens a fire while you stand next to it and you then walk away: once the rain stops, the game still thinks you are by that fire, wherever you are. The leftover is cleared within a second.
  • Travel Pause - Meads, Rested, the Forsaken power and its cooldown, and poison or burning stop counting down while a portal trip or a dungeon loads. The game already pauses your food and regeneration during loading, but not these. With a high simulation distance or a slower computer a portal trip can take 20-30 seconds, every one of them taken off your buffs - and letting poison run out unnoticed.
  • Multi-Craft Count - While you hold Shift to craft five at once, the recipe's title says "x5" for things that are made one at a time, too. The game shows the total only for recipes that make several (a recipe for 2 says "x10"), although the requirements and the craft button already count five either way. Display only.
  • Message Below Inventory - While the inventory is open, the message at the top left of the screen ("Skill improved", "Picked up ...") appears just below the inventory instead of behind it. Crafting stations keep the inventory open, so you used to hear a skill go up while cooking or crafting without being able to read which one. Display only.
  • Mine Landing - In the Infested Mines, the planks at one doorway of the cave room with the wooden bridge no longer open a way out of the dungeon. They are meant to stay, but become breakable once the dungeon has been loaded again, and the gap under them drops you out of the dungeon, which floats 5000 m above the world. The module keeps an invisible floor exactly where those planks belong.
  • Sound Voices - Eases sound effects cutting in and out where many creatures call, a problem that grows with the Simulation distance setting and is worst on Extreme, as in the Infested Mines. The game plays at most 32 sounds at once, and far loops that nobody can hear - in the Infested Mines, the lanterns on the ground 5000 m below - hold most of those 32. The module stops sounds far beyond their range (loops start again as you come back) and lets the game play up to 64 sounds at once.
  • Grapple Release - Attacks in the air no longer stop working after you have used the grappling hook. If you jump to be pulled up while hanging on the hook and the pull is cut short - you block, attack or switch weapons on the way - the game clears the pull but keeps you marked as hanging on the rope: from then on every attack you start in the air, jumping or falling, is cut off right after it begins, until you restart the game. The module clears that leftover the moment no hook point is left.

Off by default

  • Wave Depth - Waves react to the land you raise or dig: filling in the sea calms them the way a natural shore does.
  • Sea Exploring - While sailing, the map reveals more open sea around you (80 m instead of 50 m), and less in fog (20 m).
  • Head Pitch - Your character's head is raised by a set angle (10° by default). The head turns to where the camera looks, and since the camera sits behind and above you, your character keeps looking at the ground - most noticeable with VRM avatars. Only your own screen changes.
  • Oven Door - The stone oven's doors open only when you come close to them (1 m by default) instead of whenever you pass up to 3.4 m in front of the oven. Only your own screen changes.
  • Skill Breakdown - A weapon's tooltip shows what an attack costs in stamina, eitr or health before your skill takes its share off (up to a third at level 100); the module adds what it really costs you now, in brackets, the way the game already shows block armour: "Use eitr: 35 (28.1)". Hold Left Shift over a weapon or shield - in your inventory, a chest or the crafting panel - to see how much of every number in brackets comes from your skill and how much from your current effects: "Fire: 132 (33-73) skill +46, effects +0" instead of "Fire: 132 (79-119)". The bracket then shows the value at skill level 0 with no effects. Display only.

Every module is independent and can be switched on or off in the config file. The mod saves nothing of its own: remove it and you have an ordinary world.

What is on, and what is off

Every module that is on by default either makes the game behave the way its developers evidently intended, or changes nothing that affects difficulty, loot or progress. None of them contains any cheat.

Modules that change how the game plays, so that whether you want them is your call, are off by default.

Why

Two moments started this:

  • You find a Fuling camp while exploring, its bonfire burning in the night. When you come back to raid it, the fire dies just as you walk up. Nobody put it out. The camp was generated while it was still hundreds of metres away - the higher the simulation distance setting, the farther, often beyond anything you can see - and its fires have been on the clock since that moment. But the game only updates a fire's fuel while a player is within about 100 m. Until then the fire keeps showing the fuel it was created with. The moment you come that close, all the time since the camp was generated is charged at once, and if that is more than the fire could burn (about 14 hours for a camp bonfire, 7 for a camp fire pit), the fire you were walking towards goes out in front of you.
  • You queue a whole night of smelting and go to sleep. In the morning the ingots lie scattered around the smelter - the night's work made visible all at once, a small reward that is worth keeping. Then, a few seconds later, they snap together into stacks of 30. The game does that whenever more than 200 ground items are loaded, and every fish swimming in the nearby sea counts as one.

Nobody seemed to talk about these, so they are written down and fixed here. If one of these fixes is useful to you, take it: folding it into another mod is welcome (see License). The source is not published, so the technical details below say exactly what the game does, what each module does about it and what it touches - which should be all another modder needs.

Achievements

Vanilla Fix itself does nothing that affects achievements: it runs no console commands, creates no items, changes no world modifier and never touches the game's cheat flags.

One thing is not specific to this mod and worth knowing anyway. The developers ask mods to set Game.isModded, and BepInExPack Valheim does that for every modded game. In Valheim 1.0 the game stops counting achievement progress while that flag is set (Achievements.IsCheatedAtAll). So with any mod loaded through BepInEx - this one included - achievements are withheld. It is the game's rule for modded play: this mod neither adds to it nor lifts it.

If you want to keep earning achievements while playing with mods, that is a separate problem with its own solutions: several mods on Thunderstore exist for exactly that purpose.

Installation

Use a mod manager (r2modman, Thunderstore Mod Manager), or install by hand: put VanillaFix.dll into BepInEx/plugins. Requires BepInExPack Valheim; nothing else.

Configuration

BepInEx/config/mage38.vanillafix.cfg, one section per module, numbered 01 to 17. The file is re-read while the game runs. The sections of 1.0.0 (numbered 1 to 9) are renamed on the first start of 1.1.0 or later, and their settings are kept.

Multiplayer

There is no version check: players with and without the mod can play together. Each module acts on the machine it runs on:

  • Unload After Travel, Tomb Exit, Fire Warmth, Travel Pause, Mine Landing, Sound Voices, Wave Depth, Sea Exploring, Head Pitch, Oven Door, Multi-Craft Count, Message Below Inventory and Skill Breakdown only change your own game. With Head Pitch, other players still see your character's head the vanilla way; with Oven Door, each player's doors open as their own setting says; Mine Landing's floor is there for the players who have the module, and Sound Voices changes only what each player's own game plays.
  • Grapple Release acts on your own character only. It sets your animation state the way the game does, so the other players see you corrected too.
  • Camp Fires, Ground Item Merging and Station Range act through whoever owns the objects or the zone - usually the player standing nearby. Install the mod on every player's game for consistent results. On a dedicated server the server itself does nothing; the players' copies do the work.

Compatibility

Since nothing is patched (see "How every module is built" under Technical details), other mods are not overridden, and if a game update changes something a module needs, that module switches itself off and says so in the log while the rest keep working. Tested with Valheim 1.0.21.

Technical details (advanced)

For modders and the curious: for each module, what the game does, what the module does about it and exactly what it touches.

How every module is built

The same rules hold for all of them:

  • Nothing in the game's code is replaced. There are no Harmony patches and no compile-time reference to the game. A module reads the game's own data and calls the game's own methods through reflection. Other mods are not overridden.
  • Nothing of the mod's own is saved. No files besides the config, no custom data in the world or on the character. The only saved values a module writes are ones the game keeps anyway, written the way the game writes them: a fire's fuel (Camp Fires) and explored map pixels (Sea Exploring). Remove the mod and you have an ordinary world.
  • It fails closed. If a game update changes something a module needs, that module switches itself off and says so in the log instead of guessing, and the others keep working. An error inside a module is caught and logged, not passed on to the game.
  • It is light. Modules read the lists the game already keeps (loaded stations, ground items, locations, water volumes, effect areas, pieces, sound effects) instead of searching the scene, on timers of a quarter of a second to two seconds. Where the game keeps no list (the rooms of a dungeon), Mine Landing asks the physics engine for the colliders within 32 m of you, and only while you are inside a dungeon. The only things done every frame are reading a single flag per loaded camp fire, checking whether you are teleporting, checking whether your grappling hook point is still there (and, only when it is not, two animation flags), checking whether the multi-craft key is held while the inventory is open and, with Head Pitch on, re-aiming your own character's head (with Skill Breakdown on, also comparing the text of an open tooltip with what it last wrote).

Unload After Travel (on)

In the game. Unused assets are freed (Game.CollectResources) only on respawn, pause and sleep, and even that is skipped if it happened in the last 20 minutes. A portal trip never triggers it, so a quick visit to another biome leaves that biome's textures in video memory; on a card that is nearly full they spill into system memory and the game stays slower until restarted. The console command cr fixes it at once.

The module does the same by itself:

  • a few seconds after any teleport (optionally only above a minimum distance),
  • while on a ship, every 3000 m (straight line) from where the last unload happened,
  • on a key, if you set one.

Each unload costs one short hitch.

It touches nothing in the world. It calls Game.CollectResources, the method behind cr.

Camp Fires (on)

In the game. A fire's fuel is updated by Fireplace.UpdateFireplace: every 2 s it subtracts the time since the fire's last update (lastTime) divided by m_secPerFuel. Only the machine that owns the fire does this, and a player owns just what lies within 1.5 zones (96 m) of the centre of the zone they stand in (ZNetScene.PointInsideActiveArea) - whatever the simulation distance. The simulation distance decides something else: how far away zones are generated and objects created. So three things happen at three distances:

  1. A few hundred metres out, the camp's zone is generated. Its fires get their starting fuel (camp bonfire 10 of 10, camp fire pit 5 of 10; one unit lasts 5000 s) and their lastTime. The clock runs from here.
  2. Closer, the fires are created and drawn, but not updated: they show the fuel stored for them, however old it is.
  3. Within ownership range the first update subtracts everything since the last one - usually since the camp was generated - in one go. A fire that looked fine a second ago is suddenly empty.

The module looks at each of a camp's own fires separately. It keeps the fire near full, and lights it again if it has burnt out, while both of these are true:

  • within 20 m of the fire there is a camp spawner that has not spawned yet (nobody has come close), or a Fuling that one of the camp's spawners spawned;
  • the fire is not inside a player base. This is the same test the game uses to stop monsters from spawning (EffectArea.IsPointInsideArea with PlayerBase): workbenches and other stations, and the fires, torches, beds and portals you place.

Otherwise the module leaves the fire alone: it burns down normally and can be refilled by hand. A kept fire that has just come into your ownership gets its lastTime brought up to date before the game's own update can charge it for the time it was out of range, so it does not flicker either. (Arriving by teleport right next to a camp, the fires can be created already in your ownership, and then the game's update comes first: the fire goes out and is lit again on the module's next check, a moment later.) Objects appear a few per frame after a load, so a fire is not refilled while a piece with a player-base area within 45 m of it has not been created yet or was created less than 2 seconds ago: the base test could miss such a piece.

So an untouched camp keeps all its fires. While you clear a camp, the fires near the remaining Fulings are the last to be let go. Fulings that chased you far away and never came back no longer count, and penning a Fuling in next to a bonfire does not buy an eternal fire once you build a base around it. Random Fuling packs wandering the plains at night are ignored on purpose. Covers Fuling camps and the torches of Hildir's plains fortress (configurable).

It touches two values the game stores for every fire, its fuel and its last-update time, and then calls the game's own Fireplace.UpdateState so the flames match. Only fires that belong to the listed locations and were not built by a player are written to, only by their current owner - the one machine the game itself lets update that fire - and only while the rule above keeps them. Since nothing can be written outside ownership range, a fire that had already burnt out before the mod was installed stays dark from a distance until you come within about 100 m of it once.

Ground Item Merging (on)

In the game. Every 10 s each ground item checks whether more than 200 ground items are loaded (ItemDrop.s_instances.Count > 200, the number is compiled in) and, if so, merges once with items of the same kind within 4 m (AutoStackItems). Catchable fish are ground items too, so near the coast the count is above 200 all the time. Swimming fish do not merge with each other; they only inflate the count.

The module counts without fish (Ignore fish) and compares that with the threshold (default 200, adjustable). While the count is at or below it, nothing merges; once the items you dropped really pass the threshold, the game merges them on its own schedule.

It touches one runtime flag on loaded items, ItemDrop.m_haveAutoStacked, which only AutoStackItems reads and which is never saved: setting it makes the game's merge return at once, clearing it lets the merge run. Switching the module off clears every flag it set. (With a threshold below 200 it also calls the game's own AutoStackItems.)

Station Range (on)

In the game. Patch 0.217.14 announced that "enemy spawn block and item despawn now matches workbench build radius", and 0.217.22 that "increased crafting station radius should now block spawn area". So a workbench's spawn protection grows with its extensions, and an artisan table protects 40 m. The mechanism is CraftingStation.GetExtensions(), which writes the build range into the radius of the station's player-base trigger (m_effectAreaCollider).

But GetExtensions() is only reached after you walk up to the station (or use it). Right after a station is loaded

  • game start, or coming back from far away - it protects only the 20 m of its prefab, and raids or animals can spawn inside your base. Players have been puzzled by this for years: forum threads report creatures spawning well inside an artisan table's range, and the answer they usually get is that its protection was only ever 20 m - which contradicts the patch notes above. The behaviour has not been addressed so far.

The module calls the same GetExtensions() on every loaded station (the game's own list CraftingStation.m_allStations) every 2 s, so the full radius applies as soon as a station is loaded.

It touches nothing itself: the radius is set by the game's method, to exactly the value the game sets once you walk up. It never makes a radius larger than the game itself does, and nothing is saved.

Tomb Exit (on)

In the game. The Smouldering Tomb, the Black Forest dungeon of Hildir's quest, cannot be left the normal way. From inside, the bright exit shows no "Exit" prompt and walking into it does nothing; the prompt only flickers up when you look past the edge of the opening at an angle.

A dungeon's exit is an invisible trigger with a solid slab behind it: looking at the slab gives the prompt, and walking into the trigger leaves the dungeon too. The entrance room is built for an exit that sits 1 m inside it, which is where the ordinary burial chambers have it. Dungeons whose interior is aligned with the zone grid (Location.m_useCustomInteriorTransform) need their exit authored 1 m further forward to end up there, and the mountain caves, Hildir's cave and the Mistlands entrances all have it that way. The Smouldering Tomb's exit was left where it was, so slab and trigger sit 1 m behind the end of the room, out of reach.

The module moves that exit 1 m forward, to the place it has in every other dungeon of this kind. The spot where you arrive when entering moves with it.

It touches the position of one scene object in a loaded Smouldering Tomb (Interior/ExteriorGateway). Nothing is networked or saved, and each player's game has its own copy of the exit. An exit that is already in the right place is left alone, so the module does nothing once the game's data is corrected; switching it off puts the exit back.

Fire Warmth (on)

In the game. The warmth around a fire is an effect area (EffectArea, type Heat) that keeps a list of who touches it: Unity's trigger messages add you when you step in and remove you when you step out. Every physics step the area calls Character.OnNearFire for everyone on that list, without looking at the distance, and that keeps the fire icon and its warmth on you. Unity sends no exit message when a trigger is switched off while you stand in it, and a fire switches its warmth off while it is wet (or out of fuel): the warmth sits in the part of the fire that is shown only while it burns dry. So, standing by an open fire when rain starts, then walking away: once the rain stops and the fire dries, its warmth comes back with you still on its list, and you have the fire icon wherever you go - in the rain, in the middle of a forest - until that fire unloads or you walk through its warmth again. Areas that give a status effect to whoever stands in them use the same list and can stick the same way.

The module checks once a second, in the game's own list of effect areas (EffectArea.s_allAreas), whether an active area of these kinds still counts you although you are clearly outside it (outside its bounding box plus 1 m). If so, it takes you off that area's list - what the missed exit message would have done. A leftover is gone within a second; standing by a real fire is never affected.

It touches one runtime list per such area (m_collidedWithCharacter), removing only your own character, and only while you are certainly out of the area. Nothing is saved, and the areas work as before for everyone else.

Travel Pause (on)

In the game. A portal trip takes at least 8 seconds and then waits until the area around the destination has loaded (Player.UpdateTeleport); a dungeon entrance takes 2 seconds plus the load. For that time the game holds you still on purpose: Player.UpdateStats returns at once while you teleport, so your food timers and the regeneration of health and stamina stop, and damage is ignored. Two things were left out: status effects (SEMan.Update, run from Character.CustomFixedUpdate) and the Forsaken power cooldown (Player.UpdateGuardianPower). So meads, Rested and an active Forsaken power lose as many seconds as the load takes - more with a slow disk or a high simulation distance than with a fast one - and poison or burning quietly runs out, since its damage is ignored meanwhile.

The module takes a snapshot when a teleport starts and writes it back every frame and every physics step until the teleport ends: the elapsed time of every status effect with a duration and what is left of its work (poison and burning damage left, healing ticks left), the Forsaken power cooldown, and health, stamina and eitr, so that a healing tick that still fires during the load gives nothing extra. The rules of the trip become the same for every load time, as the game already intends for food. Hold harmful effects (on) and Hold Forsaken power cooldown (on) can be switched off separately. Effects that start during the load, such as the weather at the other end, are left alone.

It touches runtime values of your own character only (StatusEffect.m_time and the work-left fields of poison, burning and healing effects, Player.m_guardianPowerCooldown, health, stamina, eitr), and only while you are teleporting. Tick timers are deliberately left running, so nothing fires twice. Nothing is saved beyond what the game saves anyway.

Multi-Craft Count (on)

In the game. Holding Shift (or pressing the left stick on a gamepad) at a crafting station crafts five at once (InventoryGui.m_multiCraftAmount): the requirements are multiplied and the button reads "Craft x 5". The title above them shows the total only when the recipe makes more than one item (Recipe.m_amount > 1, then "name x total"), so a recipe for 2 says "x10" while a recipe for 1 keeps its bare name. Upgrades cannot be crafted five at once and are not affected.

The module runs after the game has updated the crafting panel each frame (InventoryGui.UpdateRecipe, from InventoryGui.Update). If the game is crafting five at once - the same test the game itself makes: the multi-craft key held, no upgrade selected - and the selected recipe makes one item, it writes the title in the game's own format ("name x5"). It changes the title only while it is exactly the item's name as the game has just written it, so a title set by another mod is left alone.

It touches the text of the recipe title on your own screen and nothing else. The game writes the title again every frame, so letting go of Shift or switching the module off brings the bare name back at once. Nothing is saved.

Message Below Inventory (on)

In the game. Short messages such as a skill going up or an item picked up are shown at the top left (MessageHud.MessageType.TopLeft; only the very first level of a skill goes to the centre of the screen). Their text and icon sit under TopLeftMessage, and the inventory (Inventory_screen) is the next element in the same GUI, so it is drawn on top of them and covers them completely. Crafting stations open the inventory along with the crafting panel, so a skill that goes up while you cook or craft plays its sound, but its message stays hidden.

The module runs after the game's own updates each frame. While the inventory is open (InventoryGui.IsVisible()), it moves the message down so that its top sits just below the lowest open inventory panel: your own inventory (InventoryGui.m_player), or the chest below it while one is open (m_container). The panels' corners are measured every frame, so a different GUI scale or a mod that changes the size of the inventory is followed. When the inventory closes, the message goes back to where the game put it.

It touches the position of the top-left message on your own screen and nothing else. Switching the module off puts the message back at once. Nothing is saved.

Mine Landing (on)

In the game. One room of the Infested Mines, dvergr_stone_open01 - a cave with a chasm crossed by a wooden bridge and a stone doorway at each end - has a landing of three 6 m planks at one of its doorways (dvergrtown_wood_beam (6) to (8)), level with the floor of the next room. In the room prefab these planks, and the three at the other doorway, have no Destructible: unlike the beams of the bridge, they are meant to stay. But DungeonGenerator.PlaceRoom copies a room's networked parts out of the room as they are only when the dungeon is first generated, and the saved object keeps nothing but the prefab name. The next time the area loads, ZNetScene rebuilds the planks from the registered prefab dvergrtown_wood_beam - the beam of the bridge, with 300 health - so from then on they can be broken, and they drop wood. Under that landing, between the top of the cave wall and the edge of the next room's floor, is a gap of 0.4 to 0.6 m that leads under the next room: out of the dungeon, whose rooms float 5000 m above the world. Without a feather cape the fall is fatal. The other doorway has the stair's own floor under its planks and stays closed. No other networked part of any room of this dungeon changes this way after a reload.

The module gives every loaded dvergr_stone_open01 an invisible box with exactly the size and place of those three planks. Where the planks are still there it lies inside them and changes nothing; where they have been broken it is the floor they were, so worlds in which they are already gone are covered too. The planks themselves are left as the game has them. A room is given the box only when it has the expected size and its stone doorway sits where expected, so a room that a game update has changed is left alone, and logged. A dungeon's rooms are children of its DungeonGenerator, which no game list holds, so the module finds them from the colliders within 32 m of you, four times a second, and only while you are inside a dungeon (above 3000 m, the game's own Character.InInterior test).

It touches nothing of the game's own: it adds one collider object (VanillaFix_LandingFloor) under each such room, in your own game only. Nothing is networked or saved, so the floor is there for the players who have the module; switching it off removes the boxes.

Sound Voices (on)

In the game. Unity really plays at most 32 sounds at once: the game keeps the engine's default (AudioManager, 32 real voices and 512 virtual ones) and never changes it. Sounds beyond that are kept silent ("virtual") until a voice is free. Music, ambience, wind and the sea are priority 0 and always keep theirs; every sound effect - creatures, your own skills and footsteps, pieces - is priority 128, and they share the rest by how loud they are. Many sounds use logarithmic rolloff, which stops getting quieter at the sound's max distance instead of going silent, so a loop far out of its range still counts as a sound being heard and holds a voice. How many are loaded depends on the Simulation distance setting (Graphics): Classic, the default, keeps creatures and objects running within two zones (64 m each) around you, as the game did before 1.0; Extreme keeps them running within six, roughly five times as many zones, so many more creatures and loops hold voices. The figures below were measured on Extreme. The Infested Mines float 5000 m above the Mistlands, and the small locations there carry Dvergr lanterns (dverger_demister, max distance 8 m). In one mine, 22 of those lanterns 5000 m below and three fire loops 300 m away held a voice each all the time, and with music and ambience only four were left for everything else. Creature sounds have no limit of their own (ZSFX.m_maxConcurrentSources 0) and nothing culls them by distance, so with some 30 creatures loaded - every Tick and Seeker calls every 5 or 6 seconds, Seekers also buzz while flying - sound effects kept cutting in and out, most of all while casting. Measured in that mine: with the far loops stopped, the sounds close by still took up to 39 voices while casting two long staff skills and drinking several potions in a row.

The module does two things, each with its own setting:

  • Stop far sounds (on): four times a second it stops every 3D sound effect that is farther from you than four times its own max distance (Far factor), which frees its voice. A stopped loop starts again when it comes back within 80 % of that distance. If the game switches the loop's object off meanwhile - a fire put out - the module lets go of it, and the game starts it again itself when it is switched back on. Sounds the game starts and stops itself (ships, grappling points) are left alone. Muting would not do: Unity keeps a muted sound on its voice.
  • Voices (64): at start, before the main menu plays anything, the number of sounds Unity really plays at once is raised to 64 (AudioSettings.Reset). 32 leaves the game's value; mixing 64 instead of 32 costs little on today's computers. It is read at start only, so restart the game after changing it. If another mod also sets the number of voices, set it to 32 here and leave it to that mod.

It touches Unity's audio configuration (the number of real voices, at start) and whether the far sound effects it stops are playing (AudioSource.Stop and Play). The sounds are read from the game's own list (ZSFX.Instances); the only search of the scene is a single one at start, to start again any loop that is already playing when the voices are raised (normally none). Nothing is networked or saved, and only what your own game plays changes. Switching the module off starts again every loop it stopped; the number of voices stays until the game is started again. With Log on, it writes every minute how many voices were in use at most and which far sounds are stopped.

Grapple Release (on)

In the game. The grappling hook's projectile leaves a point where it lands (GrapplingPoint, or GrapplingPointSecondary for the secondary attack, which lowers you on the rope). GrapplingPoint.Activate sets an animator bool on you through ZSyncAnimation - grappling, or repell for the secondary point; a pull that brings you close switches to hanging, repell (Deactivate) - and gives you the hidden status effect GrapplingHook (no fall damage, a fall speed limit) with no end (m_ttl 0). Only GrapplingPoint.Break undoes this: the bool of the point's current mode back to 0, the effect given an end 2 s later (3 s for the secondary point), and the point destroyed. Break runs from the point's own update - when you block, attack, unequip the hook or get more than 60 m (secondary 70 m) away - and only while the point's network object is valid. Jumping while you hang more than 5 m from the point pulls you up to it (Character.Jump -> GrapplingPoint.Pull), and Pull switches the point to pulling, setting grappling but leaving repell at 1. If that pull is cut short (block, attack, switching weapons), Break clears only grappling and destroys the point: repell stays 1 with nothing left to clear it. A second, rarer way: the point is not saved (ZNetView.m_persistent off) and has no clean-up of its own, so when its area unloads, ZNetScene.RemoveObjects invalidates and destroys it and Break never runs. The player's animator has two transitions that can start from any state, -> Grappling [grappling & falling] and -> Repell [repell & falling], and the game sets falling once you have been off the ground for 0.1 s, rising too (Character.UpdateMotion). So with a bool left at 1, every moment in the air throws you back into that state: an attack started in the air plays its first 0.1-0.2 s (the stamina or eitr is spent and its start sound plays) and is cut off before its hit or projectile. On the ground nothing shows. Restarting the game clears it.

The module checks every frame whether one of your hook points is alive (GrapplingPoint.m_localGrappler). While one is, it does nothing. When none is but one of those bools is still 1, it does at once what Break would have done: the bools back to 0 through your ZSyncAnimation. There is no frame where that is legitimate: Break destroys its point at the end of the frame, and when it hands you over to the secondary point it activates that one within the same call. Should a bool be 1 again right after being cleared, the module tries only every 0.25 s from then on. Four times a second it also looks for the GrapplingHook effect still on with no end and gives it the end time of the hook's point prefab (ResetTime, m_ttl = m_ttlSE, m_maxMaxFallSpeed = 0).

It touches two animator bools of your own character, set the way the game sets them, and the end time of one status effect on you, found by its name GrapplingHook. Other effects - such as the feather cape's SlowFall, which also takes away fall damage - are never touched. Nothing is saved.

Wave Depth (off)

In the game. Shallow ground calms the waves: the wave height is scaled by a depth factor taken from the four corners of each zone's water (WaterVolume.m_normalizedDepth). Those corners are read once, when the zone loads and before its terrain edits are applied, so the water only ever sees the ground as it was generated: filling in the sea does not change the waves.

The module compares each loaded water volume's four factors with the terrain as it is now and, when they differ, writes the new factors and calls the game's SetupMaterial(), so the waves you see and the waves that move ships and wet your feet both follow raised and dug terrain. Raised terrain weight counts only part of each raise if a fully calm sea next to your build feels wrong.

It touches runtime fields of the loaded water volumes (m_normalizedDepth, m_oneDepth). Nothing is saved; without the module a zone simply loads with the generated values again. It is off by default because it changes how the sea behaves next to anything you build up.

Sea Exploring (off)

In the game. The minimap reveals a circle of Minimap.m_exploreRadius (50 m) around you, the same on land, at sea and in any weather.

The module, only while you are on a ship:

  • Open water +60 %: the ocean, and any ground at or below sea level such as shallows and river mouths, is revealed within 80 m instead of the usual 50 m. Land is revealed as usual.
  • Fog -60 %, in every direction: while the weather is foggy (Misty), the explore radius drops to 20 m, land and sea alike. The map should not see further through the fog than you can.

It touches the map only through the game's own Minimap.Explore(x, y), so what it reveals is saved like any explored map (and stays revealed). In fog it lowers m_exploreRadius and puts the original value back when the fog lifts, you leave the ship or the module is switched off. It is off by default because it changes how exploring plays.

Do not use together with another mod that changes the explore radius while sailing.

Head Pitch (off)

In the game. Your character's head follows where you look, and where you look is where the camera looks (Character.GetLookDir). Every frame the game smooths that direction (CharacterAnimEvent.m_headLookDir) and has the Animator's look-at IK turn the head toward a point along it, at half weight (m_lookWeight 0.5); attacks switch the look off. The third-person camera sits behind and above your character, so with your character's front at the centre of the screen the camera - and with it the look - points down, and the head bows toward the ground. Avatar mods that copy the game's pose onto the avatar every frame copy the bow as well, where an expressive face makes it stand out.

The module adds one small component to your own character, next to its Animator. Right after the game has aimed the head, it aims it again at the same point raised by Head pitch offset (10° by default, -30° to 30°). The setting is in degrees of the head itself: the target is turned twice as far, since the head turns about half of it. The game's weights are kept, so attacks and sitting behave as before, and the body follows only slightly (about 1° for 10°). Tested with EnhancedValheimVRM 1.4.1.

It touches nothing but where your own character's head aims on your screen. The look target the game sends to other players (s_lookTarget) is left alone, so they see the vanilla head. Nothing is saved, and switching the module off removes the component. It is off by default because how far to raise the head is a matter of taste.

Oven Door (off)

In the game. The stone oven (piece_oven) has a trigger sphere of radius 2 m with a ProximityState: as soon as a player's collider touches the sphere, the doors swing open, and they close when the last player leaves it. The sphere's centre is 1.4 m in front of the doors, so it reaches 3.4 m out. Every client opens the doors on its own screen; nothing is sent over the network. No other piece in the game uses this.

The module moves the centre of that sphere to the middle of the doors and sets its radius to Open radius (1 m by default, 0.05 m to 5 m), so the doors open when you come within that distance of them, right up to standing against the oven. Shrinking the radius alone would leave a small ball floating in front of the oven, out of reach once you stand close. This is done once on the oven's prefab, so that ovens loaded or built later get it, and once on the ovens already loaded (Piece.s_allPieces); again when you enter a world or change the setting, and nothing in between. The sphere is never switched off, since Unity sends no "left" message for a disabled trigger and a door could stay open; 0.05 m keeps the doors shut in practice.

It touches only that sphere's centre and radius. Nothing is saved, and switching the module off puts the game's own back. It is off by default because how close is close enough is a matter of taste.

Skill Breakdown (off)

In the game. The tooltip of a weapon, tool or arrow lists each damage type as "Fire: 132 (79-119)": the item's damage, and in brackets the range a hit rolls in at your skill (HitData.DamageTypes.GetTooltipString). The range is the damage times 0.25-0.55 at skill level 0, rising evenly to 0.85-1.0 at level 100; the top end reaches 1.0 at level 75 (Skills.GetRandomSkillRange). The level used is your saved level plus the levels that status effects add, rounded down (Skills.GetSkillLevel, SE_Stats.m_skillLevel), such as some trinkets at full adrenaline. Shields and weapons also show "Block armour: 48 (61)", where the bracket adds half the Blocking skill factor (ItemData.GetBlockPower). Nothing tells you how much of a bracket is your skill and how much is an effect. Damage bonuses that are applied only when a hit lands, such as a percentage added to attacks, are not part of the tooltip at all, and not shown here either.

The costs - "Use stamina", "Use eitr", "Use health" (a number, or a percentage of your current health) and "Draw stamina" - are shown as the item's bare values, but an attack takes less: 0.33 times the skill factor comes off (Attack.GetAttackStamina, GetAttackEitr, GetAttackHealth, ItemData.GetDrawStaminaDrain), a third at level 100. The stamina of a swing also follows equipment and status effects that lower attack stamina (m_attackStaminaModifier, SE_Stats.m_attackStaminaUseModifier).

The module adds to each cost line, in brackets, what an attack costs you now, after your skill and your current effects: "Use eitr: 35 (28.1)". These numbers come from the game's own methods named above, called on a copy of the item's attack with you as the attacker; the world's own stamina and eitr rates (world modifiers) are left out, as the damage ranges leave out the world's damage rates.

While you hold Key (Left Shift by default), every number in brackets - damage ranges, block armour and costs - shows its value at skill level 0 with no effects, followed by what your saved skill level adds or takes off and what everything else adds or takes off on top, in the light blue the skills dialog uses for bonus levels: "Fire: 132 (33-73) skill +46, effects +0", "Use eitr: 35 (35) skill -6.9, effects +0". The skill part is computed from the game's formulas; for costs, "effects" is simply the rest of the game's own number, so it also covers equipment, and any bonus a later version of the game adds. When the two ends of a damage range move by different amounts (above level 75 the top end stops at the item's damage, and rounding can differ by one), both amounts are given in the order of the range, low end first: "Spirit: 10 (2-6) skill +6/+4" means the low end gains 6 and the high end 4. Costs are shown to one decimal. The words are in Japanese when the game is, in English otherwise.

It covers the tooltip in your inventory and in an open chest, and the item description in the crafting panel, at the quality being crafted. Each line is changed only when it is exactly the line the game writes, computed the same way (the damage lines are also compared with the game's own GetTooltipString); a line that does not match, because the game or another mod writes it differently, is left as it is, with one warning in the log for damage or block armour.

It touches the text shown in the tooltip and in the crafting panel's description, on your own screen, and nothing else. The game writes a tooltip's text only when it changes, so the module writes its own again when you press or let go of the key, and every half second while a tooltip stays open, since effects come and go; the crafting panel is written by the game every frame anyway. Holding the key does nothing else in the inventory. Nothing is saved, and switching the module off puts the game's text back. It is off by default because it is extra information not everyone wants.

License

MIT. This software was generated entirely by an AI. Whether, and to what extent, copyright exists in AI-generated material is decided by the laws of each country; where those laws limit or deny such rights, they take precedence over the license.

CHANGELOG

Changelog

1.11.0

  • New module Location Music Echo (on by default): in an Ashlands ruined city the same music no longer plays several times over, seconds apart. A city is many ruins side by side, each playing the same track on a speaker of its own from the moment you first came near it, and the copies kept playing after you left. Now the copy heard first goes on, at the volume of the ruin you are nearest to, and never starts over; the others play silently in step with it, so one can take over without a jump when the first ruin unloads behind you. The same holds wherever places with the same music meet; different music is left as it is.

1.10.0

  • New module Raid Music (on by default): when a raid starts while you stand in a place with its own music - a Fuling camp, a Dvergr ruin, a trader - that music now gives way to the raid music the way the biome music already does: it fades out as the raid music comes, and once the raid music has faded out it comes back from where it was. The game played both at once: such places play their music on a track of their own that ignores raids, and during a raid the game only stops it from turning the other music down. While it fades out, the biome music under it stays turned down as before the raid, instead of surfacing for a moment.
  • Unload After Travel: unloads now need a teleport of at least 1000 m by default (it was 0, every teleport). The distance is measured sideways, and a dungeon door moves you only some 25-30 m sideways while lifting you 5000 m, so the same area stays loaded: an unload there freed almost nothing and only cost a hitch of up to a second. Short portal hops are skipped for the same reason. A settings file that still holds the old default 0 is moved to 1000 once; set it back to 0 if you want an unload after every teleport.

1.9.0

  • New module Grapple Release (on by default): attacks in the air no longer stop working after the grappling hook. When a pull up the hook's rope was cut short (blocking, attacking or switching weapons on the way), or the hook's point vanished with its area, the game left you marked as hanging on the rope for the rest of the session, and every attack started in the air was cut off right after it began. The module clears that leftover - the animation flags and, in the second case, the hook's hidden fall effect - the moment no hook point is left. It never touches other effects such as the feather cape's.

1.8.0

  • New module Sound Voices (on by default): eases sound effects cutting in and out where many creatures call, which grows with the Simulation distance setting and is worst on Extreme, as in the Infested Mines. The game plays at most 32 sounds at once, and in the mines far loops nobody can hear - the lanterns on the ground 5000 m below - held most of them. The module stops sound effects far beyond their range, starting loops again as you come back, and lets the game play up to 64 sounds at once (read at start).

1.7.0

  • New module Mine Landing (on by default): in the Infested Mines, the planks of one doorway landing in the cave room with the wooden bridge are meant to stay, but become breakable once the dungeon has been loaded again, and the gap under them drops you out of the dungeon. The module keeps an invisible floor exactly where those planks belong. It also covers worlds where they are already broken, and saves nothing.

1.6.0

  • Skill Breakdown: the cost lines of a weapon - "Use stamina", "Use eitr", "Use health" and "Draw stamina" - now show, in brackets, what an attack really costs you, after your skill (up to a third off at level 100) and your current effects. The game itself shows the cost before either. While the key is held they break down like the other numbers: the cost at skill level 0, then what your skill and your effects take off.
  • Skill Breakdown: when the two ends of a range move by different amounts, both are now given in the order of the range, low end first ("+6/+4"), instead of as a span from the smaller to the larger ("+4~6"), which hid which end moved by how much. Skill and effects are now separated by a comma ("skill +46, effects +0").

1.5.0

  • New module Skill Breakdown (off by default): while you hold Left Shift, the numbers in brackets in a weapon's or shield's tooltip (damage ranges, block armour) show their values at skill level 0 with no effects, followed by how much your skill and your current effects add, for example "Fire: 132 (33-73) skill +46 / effects +0". Works in the inventory, in chests and in the crafting panel. Display only.

1.4.0

  • New module Message Below Inventory (on by default): while the inventory is open, also at a crafting station, the message at the top left - a skill going up, an item picked up - is shown just below the inventory instead of behind it. Display only.

1.3.0

  • New module Multi-Craft Count (on by default): while you hold Shift to craft five at once, the recipe's title shows "x5" for recipes that make one item too, as it already shows "x10" for a recipe that makes two. Display only.
  • Oven Door: the doors now stay open while you stand right against the oven. The game's trigger sphere is centred 1.4 m in front of the doors, so with a small radius it no longer reached them, and coming closer closed the doors again. The module now also moves the sphere's centre to the middle of the doors, so "Open radius" is the distance from the doors. Descriptions corrected.
  • Oven Door: "Open radius" now defaults to 1 m (was 0.5 m), so the doors open a little before you reach them. An existing config keeps its value.

1.2.0

  • New module Oven Door (off by default): the stone oven's doors open only when you come within a set distance (0.5 m by default) instead of 2 m. Only your own screen changes.

1.1.0

  • New module Head Pitch (off by default): raises your character's head by a set angle, so that it no longer bows toward the ground because the camera looks down from behind. Only your own screen changes.
  • Config sections are now numbered 01 to 10, so that they stay in order in the file. The sections of 1.0.0 are renamed on the first start; your settings are kept.

1.0.0

  • First release: Unload After Travel, Camp Fires, Ground Item Merging, Station Range, Tomb Exit, Fire Warmth, Travel Pause (on by default), Wave Depth and Sea Exploring (off by default).