Cross-Compatibility
S1API exists so Schedule One mod developers can build against one stable API surface instead of maintaining separate mod code for Mono and IL2CPP game builds.
Schedule One can run under different runtime and loader combinations. Those environments do not expose every game type in exactly the same shape, and direct references to game assemblies can lock your mod to one runtime. S1API absorbs those differences behind framework types, lifecycle hooks, wrappers, and helper APIs.
The runtime problem
Mono and IL2CPP are different ways of running the same game code.
| Runtime | What changes for modders | Why S1API helps |
|---|---|---|
| Mono | Game assemblies are managed .NET assemblies and are easier to inspect directly. | S1API still gives you stable high-level APIs so your mod does not depend on fragile game internals. |
| IL2CPP | Game code is converted to native code and accessed through generated interop assemblies. Some members and delegate patterns differ from Mono. | S1API hides common interop differences and exposes clean C# wrappers where possible. |
If your mod references Schedule One internals directly, you may need separate code paths for each runtime. If your mod uses S1API as its boundary, most gameplay code can stay runtime-agnostic.
Loader and build targets
S1API is currently maintained for MelonLoader. Users install the packaged framework, and S1APILoader chooses the matching Mono or IL2CPP MelonLoader build at startup.
| Target | Status |
|---|---|
MonoMelon |
Supported MelonLoader build for the Mono runtime. |
Il2CppMelon |
Supported MelonLoader build for the IL2CPP runtime. |
MonoBepInEx |
Legacy source target from before the fork. It is not maintained or shipped as a supported path. |
Il2CppBepInEx |
Legacy source target from before the fork. It is not maintained or shipped as a supported path. |
The BepInEx targets remain in the repository so someone can pick them back up if they want to continue that work. The current fork does not plan around BepInEx support, and the docs, package, and examples assume MelonLoader unless a page explicitly says otherwise.
As a mod author, the important rule is to depend on the S1API package and keep your public mod surface expressed in S1API types instead of game-runtime types.
How S1API abstracts the difference
S1API provides a compatibility boundary in a few layers:
- Lifecycle hooks let your mod run when game systems are actually ready.
- Entity, item, product, phone, quest, map, and law wrappers expose stable public APIs for common modding work.
- Saveables keep mod data persistence out of direct game-runtime code.
- Reflection and helper utilities handle common member-shape differences where runtime abstractions are unavoidable.
- S1APILoader selects the framework build that matches the installed runtime.
This does not mean every possible game internal is cross-compatible. It means S1API gives you a safer path for the modding surface it owns.
Authoring rules
Use these rules when you want one mod to work across runtime builds:
- Reference
S1API.Forkedinstead of referencing Schedule One'sAssembly-CSharp.dlldirectly. - Keep mod-facing types, fields, events, and method signatures in S1API or plain .NET types.
- Use S1API lifecycle events instead of assuming game objects are ready during loader startup.
- Put runtime-specific experiments behind a small internal boundary if you absolutely need them.
- Test against both runtime builds before publishing.
Important
Directly using IL2CPP-only or Mono-only game assembly types in your mod API breaks the cross-compatible contract. Keep those details behind S1API abstractions or private implementation code.
Where to go next
- Install the framework in Installation.
- Build a minimal mod in Quickstart.
- Browse available modules in S1API Module Overview.
- Read the generated API reference when you need exact type members.