Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
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 | a day ago |
| Version | 1.1.0 |
| Download link | mage38-Vanilla_Fix-1.1.0.zip |
| Downloads | 31 |
| Dependency string | mage38-Vanilla_Fix-1.1.0 |
This mod requires the following mods to function
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.2350README
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.
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.
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 10. 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, 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, Wave Depth, Sea Exploring and Head Pitch only change your own game. With Head Pitch, other players still see your character's head the vanilla way.
- 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.20.
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) instead of searching the scene, on timers of a quarter of a second to two seconds. The only things done every frame are reading a single flag per loaded camp fire, checking whether you are teleporting and, with Head Pitch on, re-aiming your own character's head.
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:
- 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. - Closer, the fires are created and drawn, but not updated: they show the fuel stored for them, however old it is.
- 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.IsPointInsideAreawithPlayerBase): 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.
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.
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.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).