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
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.
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
MegaUiApi.Registerand its shape- Every field on
AppDefinition - Every method on
IUiBuilder,IUiRowandIUiDiagram - The names of the built-in icons
AppHandlenever being null and never throwing- Any colour you passed explicitly — it is yours, and nothing here repaints it
What may change without warning
- The default themes —
UiTheme.LightandDarkget tuned, and an app that did not choose follows them - Spacing and sizes — a header may grow by two pixels
- Anything not listed on these pages. If it is
internal, it is not a promise
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.
[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.
.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.
// 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
| Number | What it tracks |
|---|---|
| Mod version | The release, as shown on Nexus and in the log |
ApiVersion | The contract on this page. It moves far less often |