Skip to content

Managed Modules

Managed modules are the advanced alternative to the primary ordinary MelonMod starter. They are loaded and owned by the Anomaly runtime rather than MelonLoader. Use them when you want deterministic dependency resolution, typed owned subscriptions, scoped scheduling/persistence, and cleanup on module failure.

<MelonLoader UserData>/Anomaly/Modules/
+-- MyMod.dll
+-- MyMod.dll.anomaly.json

The sidecar declares schema, stable ID, module/API versions, SupportedGameVersions, dependencies, conflicts, capabilities, publisher text, and the DLL’s SHA-256. The selected game version and manifest are validated before Assembly.LoadFrom.

Each assembly must contain exactly one concrete IAnomalyMod with a public parameterless constructor.

using Anomaly.Client.Api.Events.Args;
using Anomaly.Client.Api.Events.Handlers;
using Anomaly.Client.Api.Modding;
public sealed class MyModule : IAnomalyMod
{
private IModContext _context = null!;
public void Initialize(IModContext context)
{
_context = context;
context.Subscribe<ClientReadyEventArgs>(
handler => ClientEvents.Ready += handler,
handler => ClientEvents.Ready -= handler,
OnReady);
}
public void OnEnable() { }
public void OnDisable() { }
public void Dispose() { }
private void OnReady(ClientReadyEventArgs args)
{
_context.ReportHealth("ready", FeatureHealthStatus.Healthy);
}
}

IModContext exposes the module ID, data/config directories, cancellation token, config, persistence, owner-scoped Schedule and ScheduleRecurring, command registration, typed Subscribe, disposable tracking, cleanup registration, and feature-health reporting.

Subscribe wraps the exact delegate in module fault containment and unregisters it during reverse-order context disposal. Do not subscribe raw delegates when an owned context is available. Pass disposable input, camera, capability, and model-hook registrations to context.Track. Cleanup proceeds through remaining commands, tasks, subscriptions, and resources even when a cancellation callback or another cleanup step throws; failures remain attributed to the owning module.

The SDK also includes samples/HelloAnomalyModule. Build it using the same SDK/game properties as the ordinary starter and install the DLL with its updated SHA-256 sidecar. Disabling a module stops its framework-owned work, but the assembly remains loaded until the game exits.

  • Dependency/conflict validation is all-or-none before startup.
  • A module exception is attributed to its owner, disables that module, and disposes owned resources.
  • Startup markers attribute an interrupted process to the module being initialized.
  • Repeated startup failures move the DLL and sidecar to UserData/Anomaly/Quarantine/managed-runtime/.
  • UserData/Anomaly/safe-mode.flag disables all managed modules.
  • modules.lock.json records the resolved ID, version, and hash set.

The Launcher inventories executable files before startup. Its development launch policy permits rebuilt local DLLs without per-build hash approval; the runtime still validates the module sidecar and assembly hash. Runtime ownership is not a security sandbox.

Continue to Mod Settings.