
BalrondNatureOptimizer
Smooths Balrond Amazing Nature's walking, streaming, and periodic costs with world-safe fixes and clear controls.Balrond Nature Optimizer
Performance, lifecycle, and compatibility optimizer for Balrond Amazing Nature. Amazing Nature is required and must be installed separately.
All configuration values are startup settings. Configuration Manager can save a changed value, but it cannot rebuild the current session or undo installed patches. Fully restart Valheim after every change.
Valheim's default physics step is 0.02 seconds, normally about 50 physics steps per second. This is separate from rendered FPS; Unity may run several physics steps during one slow rendered frame while catching up.
N = active characters, M = eligible grounded monsters, D = loaded supported doors. Calculated figures below are code-derived upper bounds for the audited Amazing Nature 1.3.7 binary, not runtime-profiler millisecond measurements. The Optimizer has no numeric Amazing Nature version gate; compatibility is validated feature by feature.
Technical audit table
| System | Original cadence / why heavy | Optimizer, gameplay, and world/save impact |
|---|---|---|
| Custom lava damage | Patched Character.CustomFixedUpdate, so the callback ran on every physics step for every active character: about 50 x N calls/s. After the dead/Ashlands-player/fire-resistant-monster exits, each eligible call allocated a new Vector3[9] and requested ground/lava data at up to nine positions. Upper bound: 50 x N short-lived arrays and 450 x N terrain samples/s. With 20 eligible characters that is about 1,000 arrays and 9,000 samples/s. The five-second interval controlled only damage; detection still ran every physics step even when no lava existed nearby. Creating HitData for the actual damage event was secondary. |
Optimizer: Exact-unpatches the Amazing Nature callback and clears its timer dictionary. No replacement polling or lava scan is installed. Gameplay: Disables only Amazing Nature's outside-Ashlands 10 general + 10 fire hit, Burning, and unblockable/undodgeable handling. Valheim's own lava, heat, Burning, and Ashlands mechanics remain. World/save: Runtime only. No lava texture, terrain paint, location, object, ZDO, or save record is removed. |
| Daytime Plains heat | Added three callbacks to Character.UpdateLava, UpdateHeatDamage, and UpdateHeatEffects, all reached from the character physics path. Upper bound: about 150 x N patch entries/s. Non-players exited quickly; the valid Plains player repeatedly checked Heightmap.FindBiome, daytime, water/swimming, weather, Wet/Soaked/Freezing/Shelter, equipment heat resistance, fire modifiers, heat state, damage timers, and particle dictionaries. |
Optimizer: Removes all three callbacks when the mechanic is disabled. No interval poll replaces them. Gameplay: Removes Amazing Nature's daytime heat buildup, SE_PlainsHeat, 6 fire damage every six seconds, and its heat particles. Other Plains content remains.World/save: Runtime only. Explored/unexplored zones, equipment, character saves, and world generation are unchanged. |
| Monster obstacle climbing | The callback was reached from every character physics step. An owned, awake, grounded, non-player monster could execute the full check every 0.02 seconds: up to 50 x M checks/s. A full check queried AI, target/movement, rigidbody and capsule bounds, maintained a dictionary entry, and could issue two Physics.SphereCast calls against terrain and pieces. Upper bound: 100 x M sphere casts/s; 20 eligible monsters can reach 2,000 casts/s. |
Optimizer: Removes the climbing callback, its Character.OnDestroy cleanup callback, and clears the disabled dictionary at startup.Gameplay: Monsters lose Amazing Nature's forced upward/forward boost and use Valheim movement/pathfinding, so some enemies may no longer scale steep terrain or base walls as easily. World/save: No monster, spawn, terrain, path, or building piece is edited in the save. |
| Monster door sensors | Added a MonoBehaviour.Update to every supported door prefab. Every loaded copy entered Update once per rendered frame. Valid locally owned normal doors performed Physics.OverlapSphereNonAlloc every 0.35 s; heavy gates every 0.4 s. At 60 FPS, this is 60 x D Update entries/s plus roughly 2.5-2.86 x D overlap queries/s. With 100 doors: about 6,000 Update entries and 250-286 overlap queries/s. Each query could inspect up to 32 colliders, resolve Character/BaseAI/target state, normalize a prefab name, check facing, key, ward, and allowed-monster rules. |
Optimizer: Prevents Amazing Nature's sensor registration, so placed door copies never receive the added component, Update callback, or overlap query. Gameplay: Monsters no longer use Amazing Nature's special system to open supported doors or mark ward-protected doors as attack targets. Vanilla AI may still attack structures normally. World/save: Existing doors keep their position, health, ownership, key, ward protection, and saved open/closed state. |
| Smooth stamina helper | Installed a Prefix and Postfix on every Character.CustomFixedUpdate: about 100 x N Harmony callbacks/s. It had no physics query or steady allocation, so it was smaller than lava/climb, but it scaled with every creature. The target did not contain Valheim's real stamina regeneration, which runs separately in Player.UpdateStats(float). |
Optimizer: Exact-unpatches both callbacks and does not relocate them. Moving the curve to the real regeneration method would change gameplay rather than preserve it. Gameplay: Vanilla stamina regeneration and Amazing Nature status-effect stamina multipliers continue through SEMan.ModifyStaminaRegen; only the incorrectly targeted curve is removed.World/save: No stamina value or character save data is reset or converted. |
| Deep North biome/environment | EnvMan.GetBiome and UpdateEnvironment were reached from EnvMan.FixedUpdate, at most once per rendered frame and normally up to about 50 processed cycles/s. This singleton cost did not scale with character count. Amazing Nature's stable path performed five reflection operations and at least three boxed-value allocations per cycle: approximately 250 reflection calls and 150 boxing allocations/s at 50 cycles. Override branches also created invocation arrays. |
Optimizer: Replaces the two Amazing Nature prefixes with equivalent cached delegates and direct field references. The steady path has no reflection, boxing, object array, hierarchy scan, or logging. It also stores the already calculated biome instead of Amazing Nature's stale self-assignment during an environment override. Gameplay: Preserves Deep North distance/coast rules, nearby Ocean handling, environment selection, random order/state, and camera guard; fixes the stale current-biome assignment during an override. World/save: No biome generation, map data, weather table, world object, or save data is rewritten. |
| Food and environment statuses | Amazing Nature's full food, wet/cold, mist, and sitting-heal work was reached from the local-player physics path, normally around 50 times/s. Wet/cold runs Heightmap.FindBiome; mist searches active Mister/Demister lists. Both originally landed in the same physics step four times/s. Some status-name compatibility calls also used MethodInfo.Invoke, an object[], and boxed results. |
Optimizer: Keeps two local-player dispatchers on the existing physics path. Their normal branch performs reference/timer comparisons without allocation, reflection, hierarchy scans, or logging. Full food work follows Valheim's roughly one-second food pass. Wet/cold, mist, and sitting each still run four times/s, but are phase-shifted by about one third of the interval so their geographic checks no longer form one periodic spike. The replacement also uses the exact allocation-free stable hash and removes stale SE_SitHeal.Gameplay: Food/status rules and frequency remain; an individual reaction can be delayed by at most the configured interval, 0.25 s by default. World/save: No inventory, skill, weather, world object, or permanent status data is deleted. |
| Stable-hash compatibility | The audited DLL has 81 calls through BalrondHashCompat.StableHash: 68 occur during static/type setup and 13 are dynamic. A hot dynamic path in SE_BalrondAcceleratedDebuff hashes two status strings per active debuff physics tick. The compatibility layer used reflection, allocated an invocation array, and boxed the returned integer. |
Optimizer: Replaces only Amazing Nature's compatibility method with Valheim's exact non-allocating character loop. The two most common interned literals use reference-equality fast paths. No global Update hook is added. Gameplay: Hash values and status identities remain identical; only reflection/allocation overhead changes. World/save: No save format, ZDO key, or networking identifier changes. |
| Dverger betrayal AI | The postfix runs from MonsterAI.UpdateAI, gated to about 20 calls/s for every active MonsterAI. Non-Dvergers exited after basic checks. Dvergers repeatedly ran Trim, Substring, clone-suffix removal, and numeric-suffix removal before the whitelist lookup, creating short-lived strings for typical (Clone) names. |
Optimizer: Replaces the same Amazing Nature callback instead of stacking another. Non-Dvergers still exit after null/faction checks; Dverger names are compared as string ranges without Trim/Substring allocations. The current whitelist and mark predicate are reused. Gameplay: Betrayal, mark, faction, 30 m closest-player, and alert behavior remain unchanged. World/save: No Dverger, faction, or player-mark state is rewritten in the world. |
| Fermenter sector path | Not a frame tick. The real chain is ZNetScene.CreateObject -> Instantiate -> Fermenter.Awake -> Amazing Nature editFermenter, so it runs for every fermenter instantiated from saved data, including batches during active-sector transitions. Original work repeated two linear conversion-list scans, component/name checks, and tutorial setup on every clone. |
Optimizer: Verifies the fermenter template once per ZNetScene, caches only conversion indices/references/duration, then uses an allocation-free constant-time check for matching clones. Any mismatch returns to the original Amazing Nature method. It does not patch CreateObject or sector streaming.Gameplay: Cheese and surstromming conversions, quantities, and duration remain; only a repeated sector-entry subpath is reduced. World/save: Existing fermenter contents, conversion data, ZDOs, and saved state remain unchanged. |
| Balrond Constructions core-wood hit effects | Balrond Constructions 1.4.1 registers five core_wood_wall_* prefab templates whose WearNTear.m_hitEffect contains a valid effect followed by an enabled entry with no prefab. Every qualifying structure hit calls EffectList.Create; a physical hit calls it twice. Vanilla creates the valid effect and then attempts Instantiate(null), producing repeated exceptions during projectile-heavy fights such as the Elder encounter. |
Optimizer: After ZNetScene prefab registration, checks only the five audited exact names and removes only enabled EffectData entries whose prefab reference is missing. Valid effects, their order, disabled entries, all other effect lists, and all other prefabs remain untouched. There is no per-hit patch, Update callback, sector scan, or exception catcher.Gameplay: Valid hit visuals such as vfx_SawDust still play. Only an impossible missing effect is skipped, preventing the red-console exception and its repeated stack-trace work.World/save: Existing walls are not deleted or rewritten; when loaded after a full restart they instantiate from the corrected runtime template. No ZDO or save data is changed. |
| Recipe lifecycle | Amazing Nature creates runtime recipes through ScriptableObject.CreateInstance<Recipe>. Clearing only managed lists between ObjectDB/world rebuilds could lose references while leaving native Unity Recipe objects alive. Cost accumulated across multiple world loads in one Valheim process, not per frame. |
Optimizer: On ObjectDB rebuild and confirmed Game.Shutdown, destroys only Recipe objects recorded in Amazing Nature's factory, then clears its staging/loader lists. Work is lifecycle-only; there is no world scan, cleanup coroutine, forced GC, or teleport poll.Gameplay: Recipes are rebuilt normally; learned recipes, crafting progress, items, and stations are untouched. World/save: Only Amazing Nature's temporary runtime Recipe objects are released. World and character saves are not modified. |
| Tutorial lifecycle | Conversion/station setup could register the same tutorial repeatedly as station instances or worlds were loaded. Repeated station setup is also reachable from streamed station Awake. |
Optimizer: Caches exact raw/registered tutorial names so repeated station instances return in constant time; performs bounded deduplication once at Tutorial.Awake. A dormant patch with no caller was removed.Gameplay: The intended tutorial remains available once instead of accumulating duplicate runtime entries. World/save: Tutorial progression and world objects are not erased or changed. |
| Tentacle lifecycle | Amazing Nature calls tentacle creation from its pre-vanilla ZNetScene.Awake prefix. Repeated world sessions could create another clone, and its source handling could modify vanilla TentaRoot. This is startup/lifecycle work, not sector Update work. |
Optimizer: Performs one startup-only exact-name pass over the serialized prefab list, creates/caches one Amazing Nature-specific clone for the process, removes timed destruction from the clone only, and never touches vanilla TentaRoot.Gameplay: Amazing Nature keeps its special tentacle while vanilla TentaRoot is no longer modified.World/save: No placed tentacle, ZDO, or world object is searched for or deleted. |
| Poison geysers | Generation/setup is not a per-frame Optimizer hook, but each saved geyser ZDO would otherwise instantiate a hierarchy of roughly 53 or 66 GameObjects with particles, lights, audio, colliders, AOE/effect areas, spawning, and terrain components. Multiple geysers amplify sector-streaming and rendering cost. | Optimizer: Filters both geyser definitions once during world setup. Their exact prefab templates are reduced once to lightweight Transform + ZNetView network roots so old saved records remain resolvable without instantiating the heavy hierarchy. No ZDO scan/deletion is used.Gameplay: While disabled, geyser effects, damage, audio, terrain work, and spawning do not run; an old geyser loads as an inactive network placeholder. World/save: Existing geyser records are retained. Newly generated Swamp zones receive no geyser, and re-enabling later does not retroactively fill zones already generated without one. |
| Swamp clutter and vegetation | Amazing Nature registers extra ground clutter, trees, saplings, and Guck resources. Registration itself is startup work; continuing cost comes from later placement, streaming, rendering, colliders, and active-area density. In 0.7.3 the five clutter entries were not actually matched because Amazing Nature stores m_name as balrond_<prefab>, while the filter compared unprefixed names. |
Optimizer: 0.7.4 resolves clutter by its real prefab name and removes only the Swamp biome bit from the five audited entries. Selected visual vegetation is filtered once at ZoneSystem.SetupLocations; other biome bits are preserved. Guck resource vegetation stays enabled by default. No SpawnZone, PlaceVegetation, or per-sector scan is installed.Gameplay: The configured Amazing Nature swamp clutter and selected visual trees/saplings are now genuinely absent. Guck resource vegetation remains enabled by default. World/save: Clutter is runtime cosmetic and can return when re-enabled. Existing generated trees/resources are not deleted; vegetation omitted from newly generated zones is not added retroactively. |
| Balrond clutter while travelling | Amazing Nature adds 23 clutter definitions with a combined authored m_amount of 701. Valheim generates an 8 m patch synchronously when the player crosses the clutter grid. High-quality upper bounds per patch are about 233 attempts in Meadows, 273 Black Forest, 218 Plains, 219 Mistlands, 105 Mountain, 182 Deep North, and 160 Ashlands. An attempt can run fractal, raycast, terrain, biome, ocean-depth, vegetation-mask, and cleared-ground checks. Six definitions — ormbunke_bal, mistlandsBush6, and seaBush8/9/10/11 — do not use InstanceRenderer; their authored total of 111 can become separate GameObjects per patch. |
Optimizer: Before registration, scales only Amazing Nature clutter to 50% by default and disables the six non-instanced definitions. It stores the authored values so repeated world sessions cannot scale them again. No ClutterSystem.LateUpdate patch or walking scan is added.Gameplay: Amazing Nature's small decorative ground plants are less dense, and the six listed decorative types are absent. Vanilla clutter, trees, rocks, pickables, and ZoneVegetation resources are not affected by this control. World/save: Clutter is local runtime decoration and is not stored as world ZDOs. Existing generated trees/resources and terrain are not removed. |
| Terrain-triggered clutter rebuild | Vanilla ClutterSystem.ResetGrass marks affected patches with m_reset and also sets global m_forceRebuild. The next LateUpdate(rebuildAll: true) bypasses the normal guard that stops after one missing/reset patch, so one terrain edit can regenerate many nearby patches in the same frame. |
Optimizer: Removes only the exact m_forceRebuild = true assignment inside ResetGrass. Every affected patch remains marked and is regenerated by Valheim's existing one-patch-per-rendered-frame path. ClearAll, graphics-quality changes, and their intentional full rebuilds remain vanilla.Gameplay: Grass after hoe/pickaxe/build terrain changes may fill back over several frames instead of appearing everywhere at once. World/save: The terrain edit, its saved data, vegetation masks, and world objects are unchanged; only cosmetic grass rebuild timing changes. |
| Distant terrain refresh | After the camera moves more than 256 m, vanilla waits until its 3x3 distant Heightmaps are ready and then regenerates all nine in one rendered frame. With the current 2400 m/3x3/80-width layout this is 59,049 vertices and 345,600 indices, plus texture pixels, modifiers, collision/render meshes, normals, tangents, and bounds in one spike. | Optimizer: Captures the nine already-ready build results and, with the default budget of 1, performs one Heightmap.Regenerate per rendered frame through the existing TerrainLod.Update call. It adds no updater/coroutine. Teleport/no-player paths remain immediate vanilla; an incompatible foreign RebuildAllHeightmaps patch disables this feature, and any runtime fault returns captured data before falling back to vanilla.Gameplay: The distant horizon can update tile by tile for up to nine frames, so a brief far-away seam/pop is possible. Near terrain, collision, physics, movement, and generated content do not change. World/save: WorldGenerator inputs, deterministic terrain data, heightmap saves, and ZDOs are not changed; the same ready data is consumed over more frames. |
| StaticPhysics ground checks | The Amazing Nature bundle contains 230 StaticPhysics components across 211 prefab roots. Vanilla schedules the first ground/solid-height check 20 seconds after Awake, but SUpdate never advances m_updateTime; after that, every eligible loaded object repeats the query on each SlowUpdater sweep. SlowUpdater processes up to 100 objects per rendered frame, then waits 0.1 s after a full pass. |
Optimizer: After vanilla's existing due, falling, and active-area gates, records the next eligible check at current time + 1 s by default. It changes the cadence inside the existing SUpdate; there is no added list, scan, or callback. This is a global vanilla fix and therefore also applies to non-Balrond StaticPhysics objects.Gameplay: A not-yet-falling object may react to freshly changed ground up to the configured interval later. Once falling begins, vanilla FallUpdate continues unchanged at 0.05 s; push-up/fall rules and final positions remain vanilla.World/save: Objects are not frozen, deleted, or rewritten. Any position synchronization remains the original owner/ZDO code; only the next eligibility time changes. |
| Vanilla ZDO sort delegate allocations | Current vanilla IL creates a new Comparison<ZDO> delegate in each ZNetScene.CreateObjectsSorted call, which can be reached up to 30 times/s, and in server/client ZDO send-sort passes. The sorting itself is necessary; the repeated delegate objects add avoidable GC pressure during streaming/network activity. |
Optimizer: Replaces only the three exact ldftn + newobj Comparison<ZDO> sites with three startup-cached delegates bound to the same private comparison methods. Comparator code, priorities, sort results, send selection, and network order remain identical.Gameplay: No visible or mechanical change. World/save: ZDO contents, identifiers, ownership, packet format, networking semantics, and save format are unchanged. |
| IcedTree wind callback | The audited IcedTree_bal is the only Amazing Nature prefab with GlobalWind.m_smoothUpdate = true, scheduling UpdateWind every 0.01 s: about 100 callback entries/s per active tree. Its component has no Cloth or ParticleSystem on the same GameObject, so the frequent path normally has no useful target. |
Optimizer: Changes only the exact prefab template to Valheim's normal randomized 1.5-2.5 s start and two-second cadence, about 0.5 callback/s per active tree. No tree-instance scan occurs while travelling. Gameplay: Any visual wind response supplied through this component becomes less immediate. Tree mesh, light, collision, chopping, drops, and placement remain. World/save: Runtime prefab state only; existing tree ZDOs and world generation records are untouched. |
| Ice stalagmite material poll | Outdoor stalagmite_ice_bal copies carry MaterialVariationWorld.Update. Every rendered frame it searches for an enclosing active Location; outdoor vegetation normally has none, so the component returns without disabling itself and repeats forever. |
Optimizer: Disables MaterialVariationWorld once on the exact stalagmite_ice_bal prefab template. It does not add a replacement poll.Gameplay: All copies of this exact prefab keep their authored/default material. If another mod places the same prefab inside a Location/Dungeon, its conditional dungeon material variant also will not be selected; geometry, collision, destructibility, and drops remain. World/save: Visual runtime-only change. No placed stalagmite, ZDO, resource drop, or generated zone is deleted. |
| BalrondConverter sector reload | Each sawmill/tannery/stone converter uses InvokeRepeating once/s. Instances created together during a sector load originally shared the same phase. GetDeltaTime then replays elapsed time in a loop capped at 3,600 one-second iterations; even an empty station or queued input that currently lacks enough fuel could perform thousands of zero-progress passes on its first callback. |
Optimizer: Calls the converter's own exact IsActive predicate only when the unloaded gap is at least two seconds. Empty or currently unstartable stations discard that idle elapsed block; active jobs and queues that can start keep full offline processing. The existing one-second Invoke is rescheduled once with a stable ZDO-ID phase, spreading converters across the second without another scheduler.Gameplay: Active/startable stations retain recipes, progress, output, and offline catch-up. A station that had no ability to work while loading does not retroactively spend idle seconds; its first rescheduled callback can occur less than one extra second later. World/save: Queue, job, fuel, output, accumulator, and ZDO data are not cleared. No converter or sector is scanned globally. |
| Remaining new-zone generation cost | Amazing Nature registers 181 ZoneVegetation definitions. A newly generated Deep North zone can reach a code-derived upper bound of roughly 14,800 placement candidates before terrain, surround, biome, altitude, and other rejection checks, in addition to synchronous location/dungeon creation. Logs can therefore still show Force generating hmap and dungeon spawn clusters on first exploration. |
Optimizer: Intentionally does not time-slice GenerateZone, PlaceVegetation, location/dungeon instantiation, ZNetScene.CreateObject/RemoveObjects, or ZDOMan.FindSectorObjects. Reordering those paths can change deterministic world content, collision readiness, ownership, or multiplayer behavior.Gameplay: A light hitch can remain when entering genuinely ungenerated territory; the new smoothing primarily improves travel through generated/loaded areas and periodic streaming work. World/save: New zones retain vanilla/Amazing Nature generation order and content except features explicitly disabled by their own world-generation settings. |
| Serving Tray | During database setup, Amazing Nature scans/prepares food prefabs, adds Piece/WearNTear building behavior, and can auto-register consumables. The setup is not per-frame, but every placed/spawned copy then carries added world-piece behavior. Four food displays contain roughly 197k-243k triangles each before shadows and duplicate placements. |
Optimizer: Integration is disabled by default, so food prefabs are not mutated. If manually enabled, automatic registration and the four extreme displays remain separately blockable. Gameplay: Food remains normal food and is not offered as an Amazing Nature building display by default. Existing displays may not retain full building behavior while integration/preparation is disabled. World/save: No saved display record is deliberately deleted, and world generation is unaffected. |
| Poison-geyser optimization when geysers are enabled | Original enabled templates use their authored particle limits, particle/light shadows, and spawner limits. Runtime cost scales with visible effects and active spawned creatures rather than an Optimizer tick. | Optimizer: Optional template-time caps: 512 particles per system, max 4 nearby and 12 total spawner creatures by default, particle shadows off, and light shadows off. Work runs once on exact prefab templates. Gameplay: Geysers remain active with reduced particle/shadow cost and lower creature limits. World/save: Saved geysers are not deleted. Future spawning follows the caps; world generation itself is unchanged. |
| Heavy-prefab shadows | Five audited high-cost building prefabs normally cast and receive shadows on all renderers. This is steady GPU/render cost, not a CPU Update callback. | Optimizer: Optional and off by default. When enabled, exact prefab templates have cast/receive shadows disabled once at ZNetScene.Awake; no per-instance scan runs during sector streaming.Gameplay: Optional visual tradeoff: flatter lighting and lower shadow cost; building functionality remains. World/save: Buildings, durability, placement, ownership, and saved records remain intact. |
| Material/shader handling | Amazing Nature's current bundle pass targets 293 audited materials for queue 2450 and changes culling on 116. This is mainly startup plus steady GPU/shader-state cost, not a per-frame CPU patch. Different material states can also require first-render pipeline compilation. | Optimizer: Conservative Material State Fix, Aggressive Opaque Material Restore, and Suppress Duplicate Material Passes are all off by default. Therefore the Optimizer adds no material restore pass or new shader state in the recommended configuration.Gameplay: Recommended defaults make no Optimizer material change. Opt-in modes can change appearance and first-render shader behavior for the session. World/save: No save data or asset file is modified; restart restores the selected mode. |
| Biome-message width | A prior optimizer implementation used a MessageHud.UpdateBiomeFound callback reachable from rendered-frame MessageHud.Update. The actual change only needs to happen when the HUD prefab is created. |
Optimizer: Current version widens the title once from MessageHud.Awake; there is no per-frame UI patch.Gameplay: Long biome messages receive a wider title area without a per-frame UI callback. World/save: UI only. Map and world data are unchanged. |
| Remaining asset cost | Independent of tick patches. The audited bundle exposes 2,039 reachable textures with about 682.9 MiB total all-mip data, 2,996 meshes, 2,860 MeshColliders, 7,006 MeshRenderers, and 1,209 ParticleSystems. Not all are resident simultaneously, but streamed/visible instances still cost CPU, GPU, memory, and driver work. Examples: water well about 202k active triangles; scrap-smelter extension about 142k triangles and 21 material slots; four food displays about 197k-243k triangles each. | Optimizer: The Optimizer reduces selected systems and optional content but does not rebuild or recompress the asset bundle. No periodic global object scan, Resources.UnloadUnusedAssets, or forced GC.Collect is used.Gameplay: Heavy meshes, textures, colliders, particles, and first-time shader compilation can still lower FPS or cause sector hitches. World/save: The Optimizer does not remove these assets or saved content. Full removal requires an asset-bundle rebuild or explicit content removal. |
| Optimizer periodic architecture | Periodic work is attached only where the original work already runs: the two local-player status dispatchers, two singleton EnvMan prefixes, replacement Dverger postfix, StaticPhysics.SUpdate, the existing one-second converter callback, and StableHash when Amazing Nature calls it. TerrainLod.RebuildAllHeightmaps, ClutterSystem.ResetGrass, and the three ZDO sorts are event/streaming paths rather than new loops. Verified hot branches avoid reflection and managed allocation where practical. |
Optimizer: Adds no Unity Update, FixedUpdate, LateUpdate, coroutine, global scheduler, teleport poll, object/ZDO scan, forced GC, or asset unload. It still does not patch ZoneSystem.Update, SpawnZone, PlaceVegetation, ZNetScene.CreateObject/CreateDestroyObjects/RemoveObjects, or ZDOMan.FindSectorObjects. Exact IL patterns are required; incompatible features fail open or remain vanilla.Gameplay: No optimizer-owned global tick competes with chunk streaming. Configuration changes require a full restart. World/save: No destructive cleanup or global ZDO scan is used. Host/server and clients should share world-generation settings. |
Optional controls
| Option and default | Technical behavior | Gameplay and world/save impact |
|---|---|---|
Balrond Clutter Density PercentDefault: 50 |
Scales only Amazing Nature's authored Clutter.m_amount before registration. Range: 0-100%; 100 preserves its original attempt counts, while 0 leaves the definitions registered with zero attempts. Baselines are retained so repeated world loads do not compound the percentage. |
Gameplay: Controls density of Amazing Nature's small ground decoration in every biome; it does not scale vanilla clutter or world vegetation. World/save: Local cosmetic runtime state; no ZDO, terrain, tree, rock, pickable, or save record is edited. |
Disable Non-Instanced Balrond ClutterDefault: true |
Disables the six audited definitions that create separate GameObjects instead of batched InstanceRenderer data: ormbunke_bal, mistlandsBush6, and seaBush8/9/10/11. Applied once before clutter registration. |
Gameplay: Those six decorative ground-plant types do not appear; other Amazing Nature clutter follows the density setting. World/save: Cosmetic and local; it does not delete persistent vegetation or ZDOs. |
Reduce Iced Tree Wind Update RateDefault: true |
Changes only IcedTree_bal from a 0.01-second GlobalWind Invoke to Valheim's staggered two-second cadence at prefab setup. |
Gameplay: Less immediate visual wind response; tree function, collision, chopping, drops, and placement remain. World/save: Runtime prefab state only; no saved tree is removed or rewritten. |
Disable Outdoor Stalagmite Material PollDefault: true |
Disables MaterialVariationWorld on the exact stalagmite_ice_bal template, eliminating its rendered-frame Location search. The option name describes normal usage, but the template change applies to every copy of that exact prefab. |
Gameplay: Uses the default material everywhere; a copy deliberately placed inside a compatible dungeon also will not select its conditional material variant. Geometry, collision, damage, and drops remain. World/save: Visual/runtime only; no stalagmite or ZDO is deleted. |
Skip Idle Converter Catch-upDefault: true |
On a long unloaded delta (at least 2 s), calls BalrondConverter's exact IsActive predicate once. If the station is empty or its queued input cannot currently start, discards the zero-progress elapsed block instead of entering up to 3,600 loop iterations. |
Gameplay: Active jobs and startable queues retain offline progress. Empty or currently unfueled stations do not replay idle seconds after loading. World/save: Queue, job, fuel, output, timer, and ZDO values are not cleared. |
Stagger Converter UpdatesDefault: true |
Reuses each converter's existing one-second InvokeRepeating, but assigns a stable ZDO-ID-derived initial phase from 1.000 to 1.999 s. No scheduler, list, or extra callback is created. |
Gameplay: Station state/output may refresh less than one additional second later after loading; normal one-second cadence then continues. World/save: Converter recipes, progress, inventory queues, and saved data remain unchanged. |
Fix Balrond Constructions Null Hit EffectsDefault: true |
At ZNetScene.Awake, after prefab registration, checks the exact five affected core_wood_wall_* templates and filters only enabled missing entries from their root WearNTear.m_hitEffect. No global prefab traversal or runtime damage hook is installed. |
Gameplay: Preserves every valid hit effect and removes only the call that would attempt Instantiate(null).World/save: Runtime template repair only. Existing walls, health, ownership, placement, ZDOs, and saves remain unchanged; a full restart is required. |
Smooth Distant Terrain RebuildDefault: true |
Enables allocation-free slicing of the existing 3x3 TerrainLod refresh. Ready build data is retained across a few rendered frames; teleport and compatibility-failure paths use vanilla immediately. |
Gameplay: Reduces one-frame horizon rebuild spikes; a distant seam/pop can be visible briefly. Near terrain and collision are unchanged. World/save: Same WorldGenerator output and no save/ZDO changes. |
Distant Terrain Regions Per FrameDefault: 1 |
Number of ready distant Heightmap regions regenerated per rendered frame while smoothing is enabled. Range: 1-9. With the current 3x3 layout, 1 spreads work over up to nine frames; 9 effectively keeps the one-frame rebuild. | Gameplay: Lower values favor frame-time smoothness; higher values refresh the full horizon sooner with a larger per-frame spike. World/save: Scheduling only; terrain data and world generation do not change. |
Cache ZDO Sort ComparersDefault: true |
Replaces three verified vanilla delegate-construction IL sites with cached delegates to the exact same comparison methods. If any audited pattern is not unique, that method is left vanilla. | Gameplay: No behavior change. World/save: Sorting semantics, ZDOs, network packets, ownership, and saves remain unchanged. |
Static Physics Recheck IntervalDefault: 1 s |
Sets the next ground/solid-height eligibility time after each vanilla StaticPhysics.SUpdate check. Range: 0-10 s; 0 leaves vanilla's repeated post-20-second sweep behavior. This applies globally, not only to Amazing Nature prefabs. |
Gameplay: Higher values can delay a not-yet-falling object's response to terrain changes by up to the interval; active falling remains at vanilla 0.05 s. World/save: No object is removed/frozen and original position/ZDO synchronization remains. |
Time-Slice Terrain-Triggered Clutter RebuildsDefault: true |
Keeps every ResetGrass patch marked, but prevents that method from forcing all marked patches through one LateUpdate. Valheim's existing generator handles one missing/reset patch per rendered frame. |
Gameplay: Cosmetic grass affected by terrain work can take several frames to refill. World/save: Terrain modifications and saves are unchanged; ClearAll and graphics-quality rebuild behavior stay vanilla. |
Environment Status IntervalDefault: 0.25 s |
Sets the separate repeat interval for full wet/cold, mist, and sitting-heal work. Each remains at the same frequency, but their phases are offset by about one third of the interval. The local-player dispatcher still receives the normal physics callback; its steady branch only compares references/timers. Range: 0.05-2.0 s. | Gameplay: Higher values reduce full status passes but increase wet/cold/mist/sitting response delay; phase separation avoids one combined periodic spike. World/save: Runtime only; no character save, weather, or world change. |
Optimize Poison Geysers When EnabledDefault: true |
Used only when Disable Poison Geysers = false. Applies particle, shadow, and spawner caps once to the two exact geyser prefab templates; it adds no geyser Update hook. |
Gameplay: Keeps enabled geysers with reduced visual and spawning cost. World/save: No saved geyser is deleted and geyser generation locations are unchanged. |
Geyser Max Particles Per SystemDefault: 512 |
Caps ParticleSystem.main.maxParticles for each enabled geyser particle system. Range: 32-2,000. |
Gameplay: Lower values reduce particle density, overdraw, and GPU cost. World/save: Visual only; no save or generation change. |
Geyser Spawner Max NearDefault: 4 |
Caps each enabled geyser SpawnArea.m_maxNear. Range: 0-20. |
Gameplay: Limits how many nearby creatures the enabled geyser tries to maintain. World/save: Existing world records and creatures are not directly deleted; only future spawning is limited. |
Geyser Spawner Max TotalDefault: 12 |
Caps each enabled geyser SpawnArea.m_maxTotal. Range: 0-100. |
Gameplay: Limits the total creatures maintained by the enabled geyser. World/save: Affects future spawning, not world generation or saved geyser placement. |
Disable Automatic Consumable RegistrationDefault: true |
Used only when Serving Tray integration is enabled. Replaces the automatically discovered food list with an empty list while preserving Amazing Nature's manual entries. | Gameplay: Fewer foods enter the hammer/build table when Serving Tray is enabled. World/save: Existing saved display records are not deliberately deleted; world generation is unaffected. |
Exclude Extremely Heavy Food DisplaysDefault: true |
Used only when Serving Tray is enabled. Blocks preparation and build-table registration for GoatStew_bal, ShrededMeat_bal, MeatBalls_bal, and Surstromming_bal, each audited at roughly 197k-243k triangles. |
Gameplay: Prevents new placement of the four audited 197k-243k-triangle food displays. Existing copies may lack full building behavior while excluded. World/save: Existing records remain; no world-generation entry is changed. |
Disable Shadows On Known Heavy PrefabsDefault: false |
At ZNetScene.Awake, disables cast/receive shadows once on five exact high-cost prefab templates. No per-instance sector scan is installed. |
Gameplay: Reduces GPU shadow work at the cost of flatter lighting. World/save: Buildings and their saved state remain intact. |
Conservative Material State FixDefault: false |
Restores captured cutoff and culling for selected affected materials without changing shader keywords or render queue. It can introduce a different first-render pipeline state. | Gameplay: Changes selected material cutoff/culling for the current session and may introduce a different first-render pipeline state. World/save: Visual only; no save or asset file change. |
Aggressive Opaque Material RestoreDefault: false |
Also restores opaque keywords, blend state, ZWrite, and render queue for materials classified as solid. Stronger and less compatibility-safe than conservative mode. | Gameplay: Can visibly alter materials classified as solid; intended only for controlled testing. World/save: Session/visual only; no save or asset file change. |
Suppress Duplicate Material PassesDefault: false |
Skips a later Amazing Nature material pass unless the tracked material count has increased. | Gameplay: May reduce startup work but can suppress an intentional late visual refresh. World/save: Session/visual only; no save or world-generation change. |
Performance depends on active object count, generated world density, visible assets, base size, graphics driver, and other mods. An existing .cfg keeps old values after an update. For a clean streaming A/B test, verify that both material options are false, change General / Enable Optimizer, fully restart Valheim, and traverse the same already-generated route.