ValheimEffectListCompat
Compatibility bridge for Valheim 1.0 (Unity 6): restores EffectList.Create 5-arg forwarder, Character.Message 4-arg forwarder (fixes OdinStorage), and fixes ZNetScene.RemoveObjects NRE cascade.
About this mod Author’s original text
Valheim Compatibility Bridges
-orange.svg)
A lightweight, robust two-component compatibility mod designed to restore legacy mod compatibility and eliminate game-breaking NullReferenceException cascades in Valheim 1.0 (Unity 6).
The Problems This Mod Solves
When Iron Gate upgraded Valheim to 1.0 (Unity 6000), two critical breaking changes broke dozens of existing mods and destabilized sector unloading:
- MissingMethodException on EffectList.Create
In Valheim 1.0, Iron Gate added a 6th parameter (ZDOID targetZDO) to EffectList.Create:
// Legacy signature (used by dozens of existing mods):
EffectList.Create(Vector3 pos, Quaternion rot, Transform baseChild, float scale, int itemVariant)
// Valheim 1.0 signature:
EffectList.Create(Vector3 pos, Quaternion rot, Transform baseChild, float scale, int itemVariant, ZDOID targetZDO)
Any mod compiled against older versions of Valheim throws:
System.MissingMethodException: Method not found: EffectList.Create
- AmbiguousMatchException in Harmony
When multiple overloads exist without proper parameter discrimination, Harmony lookups by method name fail with:
System.Reflection.AmbiguousMatchException: Ambiguous match found for EffectList.Create
- Unity 6 ZNetScene.RemoveObjects NRE Cascade (5,000+ Errors per Session)
In Unity 6, native C++ object destruction and managed reference lifetime behavior changed. When objects leave player sectors, ZNetScene.RemoveObjects iterates m_instances.Values. If an external mod destroyed a ZNetView or its associated GameObject during gameplay, vanilla code dereferences the dead object:
NullReferenceException: Object reference not set to an instance of an object
at ZNetScene.RemoveObjects (System.Collections.Generic.List1[ZDO] currentNearObjects, System.Collections.Generic.List1[ZDO] currentDistantObjects)
at ZNetScene.CreateDestroyObjects ()
at ZNetScene.Update ()
This causes an infinite loop of thousands of NREs every frame, severe stuttering, memory leaks, and broken entity despawning.
How It Works
This package provides a clean, two-layer architecture:
Valheim Game Launch
│
├──► 1. Preloader Patcher (ValheimEffectListCompat.dll)
│ ├─ Injected via Mono.Cecil before game assemblies load
│ ├─ Adds legacy 5-argument EffectList.Create forwarder
│ └─ Installs Harmony resolver hook for by-name patches
│
└──► 2. Runtime Scene Plugin (ValheimSceneCompat.dll)
├─ Intercepts ZNetScene.RemoveObjects
├─ Phase 1: Cleans dead/corrupted keys from m_instances
├─ Phase 2: Safely unloads entities leaving active sector
├─ Phase 3: Cleans up non-persistent owned ZDOs in ZDOMan
└─ Installs safety Finalizers on CreateDestroyObjects & RemoveObjects
Component 1: Cecil Preloader (ValheimEffectListCompat.dll)
- Location: BepInEx/patchers/Ntxfloy-ValheimEffectListCompat/ValheimEffectListCompat.dll
- Target: netstandard2.0 with zero dependencies on game assemblies.
- EffectList Forwarder: Injects a lightweight IL wrapper that forwards 5-argument calls to the native 6-argument method with a default ZDOID.None.
- Harmony Resolver: Automatically directs ambiguous Harmony EffectList.Create patches to the primary game implementation by metadata token order.
Component 2: Runtime Scene Plugin (ValheimSceneCompat.dll)
- Location: BepInEx/plugins/Ntxfloy-ValheimSceneCompat/ValheimSceneCompat.dll
- Target: netstandard2.1 standard BaseUnityPlugin.
- Safe Dictionary Sanitization: Sweeps and removes null/destroyed keys and dead references before iterating.
- Guaranteed Removal: m_instances.Remove(zdo) is guaranteed in a finally block, ensuring clean sector transitions.
- Vanilla Parity for Non-Persistent ZDOs: Correctly unregisters temporary owned entities (arrows, projectiles, transient VFX) via ZDOMan.DestroyZDO inside an isolated block, preventing world database leaks.
- Safety Finalizers: Catches and suppresses any rogue exceptions in CreateDestroyObjects and RemoveObjects, ensuring the game's main loop never aborts.
- Smart Error Throttling: Logs the first occurrenc
Install & use Install: BepInEx plugin
- The archive from playbuff is the mod itself — usually a BepInEx plugin (a .dll or a plugin folder once unzipped).
- Recommended: use a community mod manager (such as r2modman) — pick this game, import the mod, and the manager sets up BepInEx and its dependencies for you.
- Manual route: install the BepInEx loader in the game folder, then drop the unzipped .dll or plugin folder into BepInEx/plugins/.
- Launch the game — the BepInEx console logs every plugin it loads; seeing this mod in the log means it is installed.
Mods with listed dependencies need those installed too, or they will not load. Options are usually changed in-game or in the plugin's config file. In multiplayer, the host and every client need the same mods installed.
Install these first, or the mod will not work: