New backend-neutral projects
Use new when you want a MelonLoader mod that builds one backend-neutral DLL. If this is your first Schedule I mod, use the complete first mod walkthrough instead of starting from this reference page.
If you want diagnostics for an existing mod, separate Mono/IL2CPP builds, or only a few generated helpers, start with Use cases instead.
s1interop new .\MyBackendNeutralMod --apply
The scaffold includes:
- a C# project and solution;
DebugandReleasebuilds that produce onebin/Single/...assembly;local.build.props.examplefor machine-specific game paths;- an empty
S1Interop.Generated/S1Interop.BackendNeutral.csdeclaration file with commented examples; - package references needed by the generated helpers;
- a normal MelonLoader entry point with
[MelonInfo],[MelonGame], and aMelonModclass.
After creating the project:
- Copy
local.build.props.exampletolocal.build.props. - Set
MonoGamePathto analternateoralternate-betabranch install. This is required for the normal one-DLL build. - Set
Il2CppGamePathto a publicnoneorbetabranch install when you are ready to run the optional IL2CPP reference check. - If you are using unpublished local S1Interop packages, set
S1InteropGeneratorPackageSourceto the folder containingS1Interop.Generators.*.nupkg. - Open the
.slnin Visual Studio or Rider. - Build
Debug.
The normal build uses Mono reference assemblies, emits S1InteropTargetRuntime=Unknown, and detects Mono or IL2CPP at runtime. That DLL is the one you ship to both game installs.
If you intentionally want an IL2CPP reference compile while developing declarations, run it explicitly and treat the output as a check:
dotnet build .\MyBackendNeutralMod.sln -c Debug -p:S1InteropReferenceRuntime=Il2Cpp -p:S1InteropTargetRuntime=Il2Cpp
Do not publish separate Mono and IL2CPP DLLs for a backend-neutral project unless your mod still has runtime-specific code that S1Interop cannot cover yet.
For broad API exploration, you can seed the SDK from your local game references:
s1interop sdkgen . --full-sdk --apply
That adds broad type registration from local metadata. It does not create named members for every game type. For a normal mod, add one S1InteropType declaration at a time for the types where you need member facades.
Use Backend-neutral declarations to review or hand-edit the declaration file. See Generated output for what appears after a build.
Working with other S1 modding libraries
S1Interop does not replace S1API, MAPI, SteamNetworkLib, bGUI, or dedicated server APIs. Add those dependencies the same way you would in a normal MelonLoader project.
Use S1Interop for direct game access:
- generated facades for
ScheduleOne.*/Il2CppScheduleOne.*types; - type/member lookup that should survive backend differences;
- Unity component lookup helpers such as
S1Interop.Generated.S1InteropUnity; - simple public fields, properties, constructors, enum mirrors, and methods when metadata is safe;
- explicit
S1InteropMemberdeclarations for private, ambiguous, or migration-specific seams.
Keep S1API for item, NPC, shop, saveable, and UI workflows. Keep MAPI for building and model construction. Keep SteamNetworkLib for higher-level networking clients, sync vars, DTOs, chunking, and message protocols.
Use S1Interop underneath those libraries when you still need direct backend-neutral game or Steamworks access. That includes Steam P2P byte buffers, relay/session calls, callback pumping, reliable send-mode lookup, Steam ID values, and Schedule One lobby member lookup.
It does not commit game assemblies, wrapper dumps, decompiled source, prefabs, scenes, textures, or exported Unity projects.