k073l.S1MelonMod 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet new install k073l.S1MelonMod::1.0.0
                    
This package contains a .NET Template Package you can call from the shell/command line.

Schedule I MelonLoader Mod Template

This is a template for creating a MelonLoader mod for the game "Schedule I". It includes a basic structure and example code to help you get started.

Features

  • Basic mod structure
  • Useful methods for cross-backend compatibility
  • Cross-backend compatibility: IL2CPP (none/beta branch) and Mono (alternate/alternate-beta branch)
  • Easy build and test process: Select the target configuration, build the mod and the game will be launched automatically
  • Automatic testing mod loading: Comment/uncomment lines in .csproj to enable/disable automatic loading of often used mods like UnityExplorer, LocalMultiplayer

Usage

Prerequisites

  • MelonLoader and basic knowledge of how to use it
  • .NET SDK (as per MelonLoader requirements)
  • C# IDE (e.g. Rider)
  • Schedule I ownership
Preparing the directory structure

I recommend following structure:

S1-modding
├── common
│   ├── LocalMultiplayer
│   └── UnityExplorer
├── gamefiles
│   ├── Schedule I IL2CPP
│   └── Schedule I Mono

LocalMultiplayer directory should contain the mod file .dll and .bat starter. Example starter:

start "" "Schedule I.exe" --host --adjust-window --left-offset 0
timeout /t 1
start "" "Schedule I.exe" --join --adjust-window --left-offset 20

UnityExplorer directory should contain .dll files for IL2CPP and Mono versions of the mod.

gamefiles directory should contain the game files for IL2CPP and Mono versions of the game. You can use the Schedule I IL2CPP and Schedule I Mono directories to store the game files for each version.

Usage

Installation

To install this template, use:

dotnet new install k073l.S1MelonMod
Creating a new mod

To create a new mod you can use the new solution wizard: solution wizard in Rider Alternatively, you can create a new project using the command line:

dotnet new S1MelonMod -n MyNewMod \
  --S1MonoDir "" \
  --S1IL2CPPDir ""
Parameters
Name Required Description
S1MonoDir Yes Path to the Mono version of the game.
S1IL2CPPDir Yes Path to the IL2CPP version of the game.
CommonDir No Path to the common directory. (helper path, mostly useful as a variable)
UnityExplorerMono No Path to the Mono version of the UnityExplorer mod.
UnityExplorerIL2CPP No Path to the IL2CPP version of the UnityExplorer mod.
MultiplayerModMono No Path to the Mono version of the LocalMultiplayer mod.
MultiplayerModIL2CPP No Path to the IL2CPP version of the LocalMultiplayer mod.
MultiplayerModStarter No Path to the LocalMultiplayer mod starter bat file.

You can use parameters to set the paths of other params. For example, you can set the CommonDir parameter to the path of the common directory, and then use it to set the paths of the UnityExplorerMono, UnityExplorerIL2CPP, MultiplayerModMono, and MultiplayerModIL2CPP parameters. This way, you can keep your configurations readable.

Additional information

Information on S1 modding can be found in the S1 modding discord.

Bundled methods

MelonLogger Extension

Debug method allows you to log messages only when mod is built in Debug configuration. Additionally, it automatically logs caller info.

private static MelonLogger.Instance _logger = new MelonLogger.Instance("MyMod"); // logger instance needs to be created
_logger.Debug("This message will be logged only in Debug configuration");
Il2CppList Extension

ToIl2CppList<T> makes converting List<T> to Il2CppList<T> easier.

List<int> list = new List<int> { 1, 2, 3 };
Il2CppSystem.Collections.Generic.List<int> il2cppList = list.ToIl2CppList();

ConvertToList<T> naturally, converts Il2CppList<T> to List<T>.

Il2CppSystem.Collections.Generic.List<int> il2cppList = new Il2CppSystem.Collections.Generic.List<int> { 1, 2, 3 };
List<int> list = il2cppList.ConvertToList();
Utils

FindObjectByName<T> finds loaded object by name.

var sprite = Utils.FindObjectByName<Sprite>("MySprite");

GetAllComponentsInChildrenRecursive<T> gets all components of type T in children of the object.

var components = Utils.GetAllComponentsInChildrenRecursive<MyComponent>(myGameObject);

Is<T> checks and casts object to type T.

if (Is<MyComponent>(someObj, out var res))
{
    // res is MyComponent
}

GetAllStorableItemDefinitions returns all storable item definitions from the registry.

var allStorableItemDefinitions = Utils.GetAllStorableItemDefinitions();
var item = allStorableItemDefinitions.FirstOrDefault(x => x.ID == "cuke");

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.1 209 5/20/2025
1.2.0 174 5/19/2025
1.1.0 139 5/17/2025
1.0.0 220 5/11/2025