DESIGN.md covers the three-layer architecture (facts in code, Jev for tactics, gated escalation for macro). research/ documents the engine and mod surface, the Jev classifier's measured behavior, the STS2MCP HTTP interface, state shapes, failure modes, decision architecture, and a run log of the first four sessions.
6.3 KiB
01 — Game engine and mod surface
Measured on game build v0.107.1 (commit 59260271), macOS arm64, Steam.
Engine
Slay the Spire 2 is a Godot 4.5.1 (.NET) game, not Java like the original. This matters: the gameplay code is plain managed C# IL, so it can be read directly with no decompiler.
| Item | Value |
|---|---|
| Engine | Godot 4.5.1 (.NET build) |
| Runtime | .NET 9.0.7, self-contained osx-arm64 |
| Root namespace | MegaCrit.Sts2.* (2,751 types) |
| Bundle id | com.megacrit.SlayTheSpire2 |
Layout inside the app bundle
SlayTheSpire2.app/Contents/
MacOS/
Slay the Spire 2 179 MB Mach-O universal (x86_64 + arm64)
mods/ <- mods load from here
Frameworks/
libfmod.dylib, libfmodstudio.dylib
libGodotFmod.macos.template_release.framework
libspine_godot.macos.template_release.framework
libSentry.dylib
Resources/
Slay the Spire 2.pck 1.9 GB Godot pack
data_sts2_macos_arm64/ .NET assemblies + runtime
sts2.dll 9.3 MB main game assembly
sts2.xml 5.3 MB XML docs, 19,635 members
GodotSharp.dll, 0Harmony.dll, MonoMod.Backports.dll,
Steamworks.NET.dll, Sentry.dll, ...
data_sts2_macos_x86_64/ same, other arch
The free win: sts2.xml
sts2.xml is the .NET XML documentation file, shipped un-stripped. It gives
19,635 documented members with prose summaries. Example, verbatim:
ModInitializerAttribute— "Declares a class as the main entry point for the mod. If this is present, then upon loading the mod, we'll call the method namedinitializerMethodwithin the class. Otherwise, we'll create a harmony instance for the mod and callHarmony.PatchAll."
This removes most of the guesswork from modding. Query it with
~/sts2-re/docdump.py or any XML parser.
Harmony and MonoMod ship in the game
0Harmony.dll and MonoMod.*.dll are present in the shipping build. That is
a strong signal that runtime patching is a supported path, not an accident.
Official mod loader
The game has first-class mod support. Namespace MegaCrit.Sts2.Core.Modding.
| Type | Purpose |
|---|---|
ModManager |
Discovers and loads mods |
ModInitializerAttribute |
Declares a mod entry point |
ModManifest |
The JSON manifest |
ModHelper |
Content registration and hook subscription |
ModSource |
ModsDirectory or SteamWorkshop |
SettingsSaveMod |
Per-mod enable/disable and manual load order |
ModManager.Initialize is documented as loading mods "from the 'mods'
directory next to the executable, as well as Steam workshop files" and is
"called as early as possible in the game's initialization process".
Consequence: mods load at process start. Changing a mod requires a full restart. "Save and quit" to the main menu is not enough.
Mod directories
| Source | Path |
|---|---|
| Local (macOS) | SlayTheSpire2.app/Contents/MacOS/mods/ |
| Steam Workshop | Steam/steamapps/workshop/content/2868840/ |
Manifest schema (verified from a working mod)
{
"id": "STS2_MCP",
"name": "STS2 MCP",
"author": "kunology",
"description": "MCP server bridge for Slay the Spire 2",
"version": "0.4.0",
"has_pck": false,
"has_dll": true,
"affects_gameplay": false
}
Note snake_case in JSON (affects_gameplay, has_dll, has_pck), which
differs from the C# property names (affectsGameplay). The manifest filename
must match the mod id: STS2_MCP.json for id STS2_MCP.
Mod loading, from the live log
Found mod manifest file .../mods/STS2_MCP.json
Mods have been re-sorted because we detected a change or dependency order was broken.
[WARN] Mod STS2_MCP does not declare min game version. Assuming that it is supported.
Loading assembly DLL .../mods/STS2_MCP.dll
Calling initializer method of type STS2_MCP.McpMod for STS2_MCP, Version=1.0.0.0
Finished mod initialization for 'STS2 MCP' (STS2_MCP).
--- RUNNING MODDED! --- Loaded 1 mods (1 total)
[Sentry.NET] Is running modded
minGameVersion is optional but its absence produces a warning. It is worth
declaring in any mod we write.
Consent flow
NConfirmModLoadingPopup is documented as "Vertical popup used to get player
confirmation before loading mods. Renders above the capstone screens (above top
bar)." It appears over the main menu, at launch, and only when mods are
present. Consent persists as mod_settings: {"mods_enabled": true} in
settings.save.
There is also a nomods command-line argument that makes ModManager skip
initialization entirely (ModManagerState.Skipped).
Save layout
Modded and vanilla progress are isolated:
~/Library/Application Support/SlayTheSpire2/steam/<steamid>/
settings.save {"mod_settings": {"mods_enabled": true}, ...}
profile.save
profile1/saves/ vanilla progress
modded/profile1/saves/ MODDED progress
prefs.save
progress.save unlocks, card/enemy/encounter stats
current_run.save the run in progress
history/<ts>.run completed run records
Modded runs never touch vanilla saves. This was confirmed by the log line
Profile-scoped data path initialized: user://steam/<id>/modded/profile1.
Bundle signing
The app is ad-hoc signed (Signature=adhoc, flags=0x10002(adhoc,runtime))
and spctl -a already returns rejected. There is no quarantine attribute
(only com.apple.provenance). Adding files to Contents/MacOS/ breaks the
sealed-resource count but there is no enforced signature, and Steam launches
the binary directly.
Do not run Steam's "Verify integrity of game files" — it deletes the mods directory, because those files are not in the depot manifest.
Useful namespaces for a bot
| Namespace | Why it matters |
|---|---|
Core.Modding |
Official mod API |
Core.AutoSlay |
MegaCrit's own auto-play bot, shipped in the build |
Core.DevConsole.ConsoleCommands |
~40 built-in debug commands |
Core.GameActions |
Command pattern for game actions |
Core.Runs / Core.Combat |
Run and combat state |
Core.Saves |
Source-generated JSON serialization |
AutoSlayer.Start(seed, ...) runs a complete automated game with handlers for
every screen and room. It is MegaCrit's smoke-test harness and is the best
available reference for driving the game programmatically.