Mega UI
Full example
A complete working mod, in one file, using every widget there is.
This is the whole mod. There is no second class, no UI folder, and not one line of
RectTransform.
csharp
using BepInEx;
using MegaUI.Api;
using UnityEngine;
namespace ExampleMegaUiMod;
[BepInPlugin(Guid, "Example Mega UI Mod", "1.0.0")]
[BepInDependency(MegaUiApi.ModGuid, BepInDependency.DependencyFlags.HardDependency)]
public sealed class Plugin : BaseUnityPlugin
{
public const string Guid = "ExampleMegaUiMod";
// The state belongs to the mod, never to the UI. The widgets read from here
// and write back here - which is why the screen can never fall out of step
// with other code that changes these values.
private static bool _warn = true;
private static int _limit = 5;
private static int _clicks;
private void Awake()
{
var app = MegaUiApi.Register(Guid, new AppDefinition
{
Title = "Example",
Icon = UiIcon.Builtin("gauge"),
});
if (!app.Ok)
{
Logger.LogError($"Mega UI refused this app: {app.Problem}");
return;
}
app.Build(ui =>
{
ui.Header("Example app");
ui.Label("Everything on this screen was written with the Mega UI API.");
ui.Gap();
ui.Card(c =>
{
c.Row(r =>
{
r.Icon("timer");
r.Label("Frames since the game started");
r.Spacer();
r.Value(() => Time.frameCount.ToString("N0"));
});
c.Row(r =>
{
r.Label("Times the button was clicked");
r.Spacer();
r.Value(() => _clicks.ToString());
});
});
ui.Header("Settings");
ui.Toggle("Warn me about things", () => _warn, v =>
{
_warn = v;
Logger.LogInfo($"warn = {v}");
});
ui.Stepper("How many at most", 1, 20, () => _limit, v => _limit = v);
ui.Separator();
ui.Row(r =>
{
r.Label("Ready?");
r.Spacer();
r.Button("Do the thing", () =>
{
_clicks++;
Logger.LogInfo($"clicked {_clicks} time(s), limit {_limit}, warn {_warn}");
});
});
});
Logger.LogInfo("Loaded - open the store computer and look for 'Example'.");
}
}What to copy out of it
- The
[BepInDependency]withMegaUiApi.ModGuid RegisterinAwake, keeping the handleBuilddescribing the screen top to bottom
The rest is scaffolding so the example has something to show.
The csproj
xml
<ItemGroup>
<Reference Include="MegaUI">
<HintPath>$(GameDir)\BepInEx\plugins\rodopoulos\MegaUI.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="BepInEx">
<HintPath>$(GameDir)\BepInEx\core\BepInEx.dll</HintPath>
<Private>false</Private>
</Reference>
<!-- Only because the example reads Time.frameCount. A mod showing its own
data does not need even this. -->
<Reference Include="UnityEngine">
<HintPath>$(Managed)\UnityEngine.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>$(Managed)\UnityEngine.CoreModule.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>Look at what is not in that list
No UnityEngine.UI, no UnityEngine.UIModule, no Unity.TextMeshPro. A mod that draws a full screen references no UI assembly at all — that is the difference between describing a screen and building one.
Running it
- Build with
dotnet build -c Release - Copy the dll into
BepInEx/plugins/, with the game closed - Start the game, walk to the store computer
- Example is on the desktop, under the game's own icons
If it is not there, the log says why. Search BepInEx/LogOutput.log for
[ui] — and copy the file before reopening the game, because the game
wipes it on every launch.