Table of Contents

Build your first mod

This walkthrough creates a mod that prints the active Schedule I runtime to the MelonLoader console.

The default project creates separate Mono and IL2CPP builds. Use this path for your first mod. Backend-neutral facades remain experimental.

Before you start

You need:

  • Windows and Command Prompt;
  • .NET SDK 8 or newer;
  • the installed s1interop tool;
  • a Mono or IL2CPP Schedule I install with MelonLoader.

Check the tools:

dotnet --version
s1interop --version

Follow Install S1Interop if the command is not available.

1. Preview the project

s1interop new ..\MyFirstMod

The preview lists every planned file and identifies the recommended dual-runtime mode. It does not write files.

2. Create the project

s1interop new ..\MyFirstMod --apply
cd ..\MyFirstMod

S1Interop refuses to write into a non-empty target directory.

The generated ModCore.cs already reports the selected runtime:

LoggerInstance.Msg($"{ModName} loaded on {S1Interop.Generated.S1InteropRuntime.Backend}.");

You do not need to edit code before the first build.

3. Diagnose local setup

Try automatic detection:

s1interop doctor .

doctor checks:

  • exactly one project exists in the target directory;
  • the Mono install has the managed game and MelonLoader references;
  • the optional IL2CPP install has generated wrapper assemblies and MelonLoader references;
  • local.build.props is covered by .gitignore.

It is always read-only.

If a path is not detected, pass it explicitly:

s1interop doctor . ^
  --mono-game-path "D:\Games\Schedule I_alternate" ^
  --il2cpp-game-path "D:\Games\Schedule I_public"

You only need Mono for the first Mono build. Add an IL2CPP install when you are ready to build and test the IL2CPP branch.

4. Preview and write local configuration

Preview the generated local.build.props:

s1interop setup .

If the preview is correct, write the file:

s1interop setup . --apply

setup writes only local.build.props. It does not install software, edit the project, or overwrite an existing file. The target must be covered by a recognized .gitignore rule.

5. Build one runtime

Build for your installed runtime:

dotnet build .\MyFirstMod.sln -c "Debug Mono"

or:

dotnet build .\MyFirstMod.sln -c "Debug Il2Cpp"

The build writes the DLL to:

bin\Mono\Debug Mono\netstandard2.1\MyFirstMod.dll

or:

bin\Il2Cpp\Debug Il2Cpp\net6.0\MyFirstMod.dll

6. Run it in Schedule I

Copy the DLL for your installed runtime into that install's Mods folder, then launch the game.

Expected Mono log marker:

MyFirstMod loaded on Mono.

Expected IL2CPP log marker:

MyFirstMod loaded on Il2Cpp.

Unknown means the runtime probes did not find the expected assemblies. Keep the log and use Troubleshooting.

What you have now

You have a normal MelonLoader mod with:

  • explicit Mono and IL2CPP build targets;
  • compile-time S1Interop diagnostics;
  • read-only diagnosis and analysis commands;
  • ignored machine-local paths;
  • a deterministic runtime success marker.

Continue with Common tasks to analyze code, add a safe migration plan, or validate both builds.

The backend-neutral one-DLL scaffold is an experimental opt-in:

s1interop new ..\MyExperiment --backend-neutral --apply

Keep separate Mono and IL2CPP builds for production until the mod has sustained in-game validation on both runtime branches.