Mega UI

Versioning

What is promised not to break, how to check which version the player has, and what happens when the library is missing.

ApiVersion

csharp
if (MegaUiApi.ApiVersion < 1) { /* older than this mod expects */ }

ApiVersion moves only on a breaking change — something removed or something that behaves differently for code that already compiled. New widgets and new fields do not move it.

It is readonly, not const, and that is deliberate

A const is baked into your assembly at compile time. Your check would then compare against the number that was current when you built, not the one the player actually has installed — which is exactly the case you were trying to detect.

What will not break

What may change without warning

Reflection into the internals is not a contract

If you reach past the public API to get at something, that is a signal the API is missing something. Ask for it — a private field you found today is a broken mod after the next release.

When the library is missing

With HardDependency, BepInEx refuses to load your plugin at all and writes one clear line to the log. That is the behaviour you want for a mod that is only a screen.

csharp
[BepInDependency(MegaUiApi.ModGuid, BepInDependency.DependencyFlags.HardDependency)]

With SoftDependency, your plugin loads and you have to check before touching the API. Keep every mention of a Mega UI type inside one file that nothing else calls until the check passes.

Why one file, and why it matters

.NET loads an assembly the first time it compiles a method that mentions a type from it. If your main plugin class names MegaUiApi anywhere, a player without the library gets a TypeLoadException inside Awake — before any try/catch of yours can run, and with no line explaining why.

csharp
// UiBridge.cs - the ONLY file that names a Mega UI type.
internal static class UiBridge
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    internal static bool Present()
    {
        foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            if (asm.GetName().Name == "MegaUI") return true;

        return false;
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    internal static void Register() { /* MegaUiApi.Register(...) */ }
}

Present only compares assembly names, so it touches no Mega UI type and is safe to call from anywhere. NoInlining stops the compiler from folding the call into its caller and dragging the reference along with it.

Version numbers

NumberWhat it tracks
Mod versionThe release, as shown on Nexus and in the log
ApiVersionThe contract on this page. It moves far less often