Mod Loader/Plugin lifecycle
Use a ModContext to own your plugin's registrations, wait for content before looking up items, and check optional support before using it. The examples below target Mod Loader 0.7.8.
New to C# plugins? Start with Write a C# mod to set up the project and game references.
Register your plugin
Add a dependency on Mod Loader, then register once in Awake. Keep the returned context until the plugin unloads.
using BepInEx;
using DressmakerMods;
[BepInPlugin("example.content-notes", "Content Notes", "1.0.0")]
[BepInDependency("yuu.dressmaker.mods", "0.7.8")]
public sealed class ContentNotes : BaseUnityPlugin
{
private ModContext mod;
private void Awake()
{
if (!ModLoaderApi.IsReady)
{
Logger.LogWarning("Content Notes could not start. Check the loader's compatibility report.");
return;
}
mod = ModLoaderApi.Register(this);
ModLifecycleApi.WhenContentReady(mod, OnContentReady);
}
private void OnContentReady()
{
Logger.LogInfo("Content registration finished.");
}
private void OnDestroy()
{
mod?.Dispose();
}
}
Call the owned APIs and dispose their registrations on Unity's main thread. A context can also track an IDisposable from another API with mod.Track(registration). Disposing the context releases tracked resources in reverse order and continues if an individual cleanup fails. Dispose the context after any fabric-render callback has returned.
Choose the right readiness check
| Check | What it tells you |
|---|---|
ModLoaderApi.IsReady
|
Initial loader startup finished. Optional features may have been skipped. Check save loading separately before reading save data. |
ModLifecycleApi.IsContentReady
|
The startup content-registration stage finished. Some content may have been skipped; check item lookups before using their results. |
ModLifecycleApi.WhenContentReady(mod, callback)
|
Run after content registration, or immediately if that stage already finished. Deferred textures and models may still need to load. |
ModLoaderApi.Supports(id, minimumVersion)
|
The capability contract exists at the requested version and its required loader features are available. |
Initialize anything the callback needs before calling WhenContentReady: it can run before the call returns. Check item lookups and Loading problems for skipped content.
React to saves and scene changes
Once you have a context, subscribe to the events your plugin needs. Check version 2 when using the priority overload:
if (ModLoaderApi.Supports("lifecycle-events", minimumVersion: 2))
{
ModLifecycleApi.Subscribe(mod, ModLifecycleEvent.AfterSave,
context => Logger.LogInfo("Saved slot " + context.SaveSlot),
priority: 0);
}
| Event | Use it for |
|---|---|
ContentReady
|
Look up registered content. A late subscription runs immediately. |
SaveLoading
|
Clear state associated with the previous save. Wait for SaveLoaded before reading the incoming save. |
SaveLoaded
|
Read the loaded save and initialize your plugin's per-save state. |
BeforeSave
|
Prepare in-memory plugin data for the save attempt. The attempt can still fail or be cancelled. |
AfterSave
|
React after a confirmed game-save write. Check the log for separate plugin-data write errors. |
SceneLoaded, ReturnedToTitle
|
Refresh scene references or clear gameplay UI. A title scene can raise both events. |
SaveDeleted
|
Clear references to the deleted slot. |
The callback receives Event, SaveSlot, and SceneName. Higher priorities run first. Equal priorities sort by plugin ID, then registration order. If a callback throws, that subscription is removed and the error is logged; other subscribers still run.
Skip an unavailable integration
Check support when enabling an integration, and again before operations that depend on it. If support is unavailable, disable the related control or overlay and keep your other features available.
if (ModLoaderApi.Supports("inventory-events"))
ModInventoryApi.Refresh(ModInventoryKind.Fabrics);
Refresh returns false when no sidebar exists. Request refreshes outside inventory-refresh callbacks.
All capability checks return false before startup finishes. save-data also waits for content registration and is false when required save support is unavailable or protected read-only play is active. Before accessing mod.SaveData, also check that the game has loaded a save. Handle save-data errors too: a sidecar file may be damaged or use a newer format.
See capability IDs and plugin save-data and compatibility APIs. SafeLaunch skips optional loader features, so it is useful for testing whether your plugin handles missing support. Use Mod Manager to disable individual plugins separately.