Source-checkedLibraries & compatibility

Deep North Compat

by misto_fixes · for Valheim

Restores two Valheim 1.0 method overloads so mods built for the older game keep working. Needed by some older mods.

511Downloads
47d agoLast updated
BepInExLoaders
ThunderstoreSource

About Deep North Compat

From Thunderstore

Restores two Valheim 1.0 method overloads so mods built for the older game keep working. Needed by some older mods.

Deep_North_Compat

A tiny BepInEx patcher for Valheim 1.0 (Deep North). It re-adds two game methods whose signatures 1.0 changed by adding optional trailing parameters, so mods built for the older game keep working without modifying their files:

| Restored (old) overload | Forwards to (1.0) | | --- | --- | | Character.Message(type, msg, amount, icon) | Message(type, msg, amount, icon, log = false) | | SEMan.AddStatusEffect(hash, resetTime, itemLevel, skillLevel) | same + variant = 0 |

Needed by older mods such as Smoothbrain's Mining, Ranching and ComfortTweaks. Once those authors update, this package is no longer needed. It does nothing if the game already has the old overload, and a failure in it never stops the game from starting.

Caveat: adding an overload makes lookups of that method by name only ambiguous, so this shims just these two. Mods that patch these methods without argument types could be affected.

AI disclosure: this patcher was written with AI assistance (Claude, by Anthropic) and then tested on a live Valheim 1.0 dedicated server.

MIT licensed. Source (the whole patcher):

MistookenCompat.cs
// BepInEx preloader patcher: restores API overloads that Valheim 1.0 (Deep North) removed by ADDING trailing
// parameters, so mods built for the older game keep working without modifying their DLLs. Own code; does not
// redistribute any mod. Each restored overload forwards to the new method, filling the new trailing parameters
// with their declared defaults (or default(T)). Only the whitelisted methods below are touched.
// CAUTION: every added overload makes name-only reflection/Harmony lookups of that method ambiguous.
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;

public static class MistookenCompatPatcher
{
    // Type, method, old parameter types (full names) that mods still call.
    static readonly string[][] Shims = new string[][]
    {
        new string[] { "Character", "Message", "MessageHud/MessageType", "System.String", "System.Int32", "UnityEngine.Sprite" },
        new string[] { "SEMan", "AddStatusEffect", "System.Int32", "System.Boolean", "System.Int32", "System.Single" },
        // Not shimmed on purpose: Piece.SetCreator, EffectList.Create, PlayerProfile.IncrementStat. Up-to-date mods
        // (e.g. PlantEverything) patch those BY NAME; a second overload makes Harmony's lookup ambiguous and breaks them.
    };

    public static IEnumerable<string> TargetDLLs
    {
        get { yield return "assembly_valheim.dll"; }
    }

    public static void Patch(AssemblyDefinition assembly)
    {
        foreach (string[] s in Shims)
        {
            try { AddForwardingOverload(assembly.MainModule, s[0], s[1], s.Skip(2).ToArray()); }
            catch (Exception) { /* a failed shim must never stop the game from starting */ }
        }
    }

    static bool ParamsMatch(MethodDefinition m, string[] oldTypes, int count)
    {
        if (m.Parameters.Count != count) return false;
        for (int i = 0; i < oldTypes.Length && i < count; i++)
            if (m.Parameters[i].ParameterType.FullName != oldTypes[i]) return false;
        return true;
    }

    static void AddForwardingOverload(ModuleDefinition module, string typeName, string methodName, string[] oldTypes)
    {
        TypeDefinition type = module.GetType(typeName);
        if (type == null) return;
        if (type.Methods.Any(m => m.Name == methodName && ParamsMatch(m, oldTypes, oldTypes.Length))) return; // already there

        MethodDefinition target = type.Methods.FirstOrDefault(m =>
            m.Name == methodName && m.Parameters.Count > oldTypes.Length && ParamsMatch(m, oldTypes, m.Parameters.Count));
        if (target == null) return;

        MethodAttributes attrs = MethodAttributes.Public | MethodAttributes.HideBySig;
        if (target.IsStatic) attrs |= MethodAttributes.Static;
        MethodDefinition shim = new MethodDefinition(methodName, attrs, target.ReturnType);
        shim.HasThis = !target.IsStatic;
        for (int i = 0; i < oldTypes.Length; i++)
            shim.Parameters.Add(new ParameterDefinition(target.Parameters[i].Name, ParameterAttributes.None, target.Parameters[i].ParameterType));

        shim.Body.InitLocals = true;
        ILProcessor il = shim.Body.GetILProcessor();
        if (!target.IsStatic) il.Emit(OpCodes.Ldarg_0);
        for (int i = 0; i < oldTypes.Length; i++) il.Emit(OpCodes.Ldarg, shim.Parameters[i]);
        for (int i = oldTypes.Length; i < target.Parameters.Count; i++) EmitDefault(shim, il, target.Parameters[i]);
        il.Emit(target.IsStatic || !target.IsVirtual ? OpCodes.Call : OpCodes.Callvirt, target);
        il.Emit(OpCodes.Ret);
        type.Methods.Add(shim);
    }

    static void EmitDefault(MethodDefinition shim, ILProcessor il, ParameterDefinition p)
    {
        if (p.HasConstant && p.Constant != null)
        {
            object c = p.Constant;
            if (c is bool) { il.Emit(((bool)c) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); return; }
            if (c is int) { il.Emit(OpCodes.Ldc_I4, (int)c); return; }
            if (c is short) { il.Emit(OpCodes.Ldc_I4, (int)(short)c); return; }
            if (c is byte) { il.Emit(OpCodes.Ldc_I4, (int)(byte)c); return; }
            if (c is float) { il.Emit(OpCodes.Ldc_R4, (float)c); return; }
        }
        TypeDefinition def = p.ParameterType.Resolve();
        if (def != null && def.IsValueType)
        {
            VariableDefinition loc = new VariableDefinition(p.ParameterType);
            shim.Body.Variables.Add(loc);
            il.Emit(OpCodes.Ldloca, loc);
            il.Emit(OpCodes.Initobj, p.ParameterType);
            il.Emit(OpCodes.Ldloc, loc);
        }
        else il.Emit(OpCodes.Ldnull);
    }
}

Highlights

From source data

Loaders

Runs on BepInEx.

Footprint

Rated a light load on a server.

Last update

Its author last shipped an update 47d ago.

Deep North Compat on Nxeon

From our catalogue
One-click install
Supported on Nxeon Valheim servers, for BepInEx servers. We download it from Thunderstore, place it, and restart the server.
Server type needed
BepInEx
Server load
light
Smallest plan we suggest
Valheim — 4 GB (4 GB RAM). This follows our own load rating above, not a benchmark.
Latest build
1.0.0, released 2026-09-18

Game versions by loader

LoaderGame versionsNewest
BepInEx

From 1 recorded build of Deep North Compat.

Dependencies

Declared by the newest build that lists any. Required ones are installed with it on one-click installs.

Run Deep North Compat on a Valheim server

Pick a server or deploy a new one above; it is installed in one click.

What kind of mod it is

From the catalog
Listed on Thunderstore as “Content”

Libraries & compatibility

Foundations and fixes other mods build on. Usually installed because something else needs it.

Compatibility

Game
Valheim
Loaders
BepInEx
Requires
One-click install needs a BepInEx server.

Verified at the source

  • ✓ThunderstoreOfficial listing, checked 2026-10-01Open ↗
  • ✓Authormisto_fixes, as published on Thunderstore
  • ✓LicenseNot published by the sourceFree

Deep North Compat, answered

Generated from the mod’s own source data.

Which loaders does it support?

BepInEx.

Is it free?

Yes. Deep North Compat is free to download from Thunderstore.

How do I add it to my Nxeon server?

Use “Add to a server” on this page, or open NxLabs from your dashboard. We install it, restart your server and switch it on.

NxLabs

Run Deep North Compat on a Valheim server.

Deploy in about a minute from $9.99 a month, then add Deep North Compat in one click.