Example mod project made according to STS2 Early Access Mod Guide by doctornoodlearms on r/slaythespire. Ported to game v0.99+.
My process for building this mod on macOS Apple Silicon:
-
Install Godot 4.5.1 .NET version, e.g.,
Godot_v4.5.1-stable_mono_macos.universal.zipfor macOS,Godot_v4.5.1-stable_mono_linux_x86_64.zipfor Linux -
Install .NET SDK, e.g.,
dotnet-sdk-10.0.200-osx-arm64.pkgfor macOS, use nixpkgs for Linux -
Open Godot, create a project, name it
FirstMod -
In the Script tab, click File -> New Script..., select .NET as the language, name it
NewScript.cs, and fill in the following content:using Godot; using MegaCrit.Sts2.Core.Modding; using MegaCrit.Sts2.Core.Logging; namespace FirstMod; [ModInitializer("ModLoaded")] public static class FirstMod { public static void ModLoaded() { Log.Warn("MOD FINISHED LOADING"); } }
-
Copy the game's sts2.dll (e.g.,
~/Library/Application\ Support/steam/steamapps/common/Slay\ the\ Spire\ 2/SlayTheSpire2.app/Contents/Resources/data_sts2_macos_arm64/sts2.dllon macOS,~/.steam/steam/steamapps/common/Slay\ the\ Spire\ 2/data_sts2_linuxbsd_x86_64/sts2.dllon Linux) to the project root directory -
Modify
FirstMod.csprojas shown below, change the .NET version to 9.0, add a reference to sts2.dll, then click Build Project in Godot:<Project Sdk="Godot.NET.Sdk/4.5.1"> <PropertyGroup> <TargetFramework>net9.0</TargetFramework> <EnableDynamicLoading>true</EnableDynamicLoading> </PropertyGroup> <ItemGroup> <Reference Include="sts2"> <HintPath>sts2.dll</HintPath> </Reference> </ItemGroup> </Project>
-
Create
FirstMod.jsonin the project root directory:{ "id": "FirstMod", "name": "FirstMod", "author": "doctornoodlearms", "description": "", "version": "1.0.0", "has_pck": true, "has_dll": true, "dependencies": [], "affects_gameplay": true } -
Prepare an image named
mod_image.pngin theFirstModdirectory under project root directory for the mod's icon -
Go to Project -> Export..., click Add..., and select Windows Desktop
-
Under the Resources section, select Export selected resources (and dependencies), tick
FirstMod/mod_image.png, then click Export PCK/ZIP..., save asFirstMod.pck. You can also export via command line, e.g.,/Applications/Godot_mono.app/Contents/MacOS/Godot --export-pack "Windows Desktop" FirstMod.pck --headless -
Copy
FirstMod.json,./.godot/mono/temp/bin/Debug/FirstMod.dllandFirstMod.pckto theFirstModdirectory under the game'smodsdirectory, e.g.,~/Library/Application\ Support/Steam/steamapps/common/Slay\ the\ Spire\ 2/SlayTheSpire2.app/Contents/MacOS/mods/FirstMod(macOS) or~/.steam/steam/steamapps/common/Slay\ the\ Spire\ 2/mods/FirstMod(Linux), create the directory if it doesn't exist -
Launch the game
A build script is provided at build.sh to build the mod without GUI. An installation script is provided at install.sh to install the mod automatically. Tested to build & run in both macOS and Linux.
What's next:
-
Decompile the game:
git clone https://github.com/icsharpcode/ILSpy.git nix-shell -p dotnet-sdk_10 -p dotnet-runtime_10 -p powershell --run "cd ILSpy && dotnet build ILSpy.XPlat.slnf && dotnet ./ICSharpCode.ILSpyCmd/bin/Debug/net10.0/ilspycmd.dll -o $PWD ~/.steam/steam/steamapps/common/Slay\ the\ Spire\ 2/data_sts2_linuxbsd_x86_64/sts2.dll --nested-directories -p" -
Read the code, and make modifications in runtime by reflection or Harmony.
-
For runtime debugging, you can use plain logging or start Godot's Debug Server:
- In Godot, select Debug -> Keep Debug Server Open
- In Steam, set the launch option
--remote-debug tcp://127.0.0.1:6007 - Launch the game