Skip to content

Client Mod Quickstart

Use samples/HelloAnomalyMod from the matching extracted developer SDK as your first mod. It includes a console command, disposable F6 binding, visible preference, events, scheduled work, and cleanup. Follow Environment Setup to build it without a source checkout.

The smaller example below shows the same explicit lifecycle pattern for events and one recurring task. It uses only public API types and Anomaly’s compatibility metadata.

using System;
using Anomaly.Client.Api.Compatibility;
using Anomaly.Client.Api.Events.Args;
using Anomaly.Client.Api.Events.Handlers;
using Anomaly.Client.Api.Scheduling;
using MelonLoader;
[assembly: MelonInfo(typeof(MyMod.Core), "MyMod", "0.1.0", "YourName", null)]
[assembly: MelonGame("Northwood", "SCPSL")]
[assembly: MelonAdditionalDependencies("Anomaly.Client")]
[assembly: SupportedGameVersion("14.2.7^")]
namespace MyMod;
public sealed class Core : MelonMod
{
private ScheduledTask _heartbeat;
public override void OnInitializeMelon()
{
RoleEvents.Changed += OnRoleChanged;
ClientEvents.Ready += OnReady;
ClientEvents.Disconnected += OnDisconnected;
}
public override void OnDeinitializeMelon()
{
RoleEvents.Changed -= OnRoleChanged;
ClientEvents.Ready -= OnReady;
ClientEvents.Disconnected -= OnDisconnected;
CancelHeartbeat();
}
private static void OnRoleChanged(PlayerRoleChangedEventArgs args)
{
MelonLogger.Msg(
$"Role: {args.PreviousRole?.Type} -> {args.NewRole?.Type}");
}
private void OnReady(ClientReadyEventArgs _)
{
CancelHeartbeat();
_heartbeat = Scheduler.Every(
TimeSpan.FromSeconds(1),
() => MelonLogger.Msg("MyMod heartbeat"));
}
private void OnDisconnected(ClientDisconnectedEventArgs _)
{
CancelHeartbeat();
}
private void CancelHeartbeat()
{
_heartbeat?.Cancel();
_heartbeat = null;
}
}
  • SupportedGameVersion is the Anomaly/Launcher compatibility contract. 14.2.7^ accepts the supported 14.2 patch line and rejects 14.3.
  • MelonAdditionalDependencies uses the runtime assembly name Anomaly.Client, not the MelonInfo display name Anomaly. It orders initialization without adding a compile reference to the runtime DLL.
  • PlayerRoleChangedEventArgs exposes Player, PreviousRole, and NewRole.
  • Public Scheduler methods return handles. Peer mods retain and cancel their own handles; global reset, pause, resume, and owner-wide cancellation are internal.
  • InputRegistry.Register returns IDisposable. Unsubscribe named input handlers, then dispose the binding during deinitialization. Disposal is silent and retains the user’s saved key override.
  • ClientEvents.Ready and Client.IsClientReady report the client scene-ready lifecycle signal. LocalPlayer, world collections, and EnrollmentId may still be unavailable; check the actual prerequisites at the point of use.
  • Disconnected also covers failed handshake/retry transport attempts. It need not follow Ready, and cleanup must be safe to repeat. The sample cancels and clears its task handle idempotently.
  • Subscriber exceptions are isolated, but your handler should still report its own failures clearly.

The packaged starter uses example.hello for Anomaly registrations and example_hello for its raw MelonPreferences category. Keep raw preference category IDs free of dots and use underscores; the supported loader treats dots as TOML paths, which can lose saved entries. See Mod Settings.

  1. Build Release/x64 against the staged SDK and the selected 14.2.7-compatible game references.
  2. Put MyMod.dll in GameRoot/loadouts/<name>/local/Mods/.
  3. Launch the loadout. The development launch policy permits rebuilt local DLLs without per-build hash approval.
  4. Connect to an Anomaly server and inspect Latest.log. Run anomaly.status or anomaly.status --copy for a sanitized diagnostic summary.

For the packaged starter, install HelloAnomalyMod.dll, run example.hello.hello or press F6, and open Settings > Mods > Hello Anomaly. Disable and reset the greeting to check live settings. Connect, disconnect, and reconnect to verify that only one recurring callback remains. Keep game, loader, API, and Shared reference DLLs out of your mod’s output package.

Continue to Client API Tour.