Patch Feature 3

Slay the Spire 2 V101 Modding Guide

V101 lays down the first real mod-loading floor: explicit load states, manifest fields, dependency checks, source types, restart gating, and two hook surfaces for combat and run data.

5Load states
2Source types
6Error readouts
2Hook delegates

The game now tracks Loaded, Failed, Disabled, and AddedAtRuntime explicitly instead of treating every miss the same way.

First-load consent is gated behind a restart warning, and newly detected changes still need a relaunch to become active.

Manifest, dependency, and duplicate-id checks are all wired before load is allowed to continue.

Load states

The state model is simple and that is exactly why it works

The list is short enough to understand at a glance. That matters. A mod screen full of vague half-states would be garbage.

None

Detected, not processed yet

This is the untouched state before the loader decides whether to skip, fail, or load the package.

Loaded

The package passed validation and finished initialization

If the mod DLL, pack, and initializer path all complete cleanly, the state flips to Loaded.

Failed

Validation or initialization broke

Duplicate ids, missing dependencies, circular chains, assembly load failures, and thrown exceptions all land here.

Disabled

The package is known, but intentionally skipped

This state is used when the player has not agreed to load mods yet or when the mod is disabled in settings.

AddedAtRuntime

Seen too late to load in the current session

If a new package shows up after startup, it is detected, but not loaded into the live session. The game marks it and asks for a relaunch instead.

Manifest fields

The manifest schema is small but already useful

The fields say what they need to say and stop there. That is good taste. Short metadata beats an overdesigned format full of dead fields.

Identity

id, name, author, version, description

These are the basic display and lookup fields. The mod list, detail panel, duplicate-id check, and error copy all lean on this block first.

Payload

has_pck and has_dll

The loader checks whether the package expects a resource pack, an assembly, or both, then looks for matching files named after the mod id.

Dependencies

dependencies is a real gate, not decoration

If the declared dependency list is not satisfied, the mod does not load. Missing and circular dependency cases both surface as explicit failures.

Gameplay flag

affects_gameplay defaults to true

That field is already present in the manifest model, which is a good sign that the game is thinking ahead about save, run, or leaderboard boundaries.

Error surface

There are six player-facing error readouts right now

That is enough. Each one maps to a real failure lane instead of burying everything under one useless red sentence.

MOD_ERROR.NONE

Clean load summary

When the set loads cleanly, the game can print a plain summary of loaded packages instead of treating modded startup like a warning by default.

MOD_ERROR.DUPLICATE_ID

Duplicate ids fail fast

If two packages claim the same id, load stops for that package immediately. That is exactly the right call.

MOD_ERROR.CIRCULAR_DEPENDENCY

Circular chains are blocked outright

Dependency loops are reported with the chain itself, so the failure is readable instead of mysterious.

MOD_ERROR.MISSING_DEPENDENCY

Missing requirements are listed by name

The loader reports how many dependencies are missing and which ones failed to show up.

MOD_ERROR.ASSEMBLY_LOAD

Initializer failure gets its own lane

If the assembly exists but initialization does not complete cleanly, the game records that as a specific assembly-load failure.

MOD_ERROR.EXCEPTION

Thrown exceptions stay visible

Unhandled loader exceptions are caught, typed, and attached to the mod entry instead of vanishing into a generic failure bucket.

Hook surface

The first hook layer exposes combat and run state

The delegate surface is narrow, but it is enough to show the intended direction. The game is opening the door carefully instead of blowing the wall out on day one.

Combat hook

CombatHookSubscriptionDelegate

The combat hook receives CombatState and returns an enumerable model set. That makes it a natural lane for combat-scoped extensions.

Run hook

RunHookSubscriptionDelegate

The run hook receives RunState and returns an enumerable model set, which is the matching shape for run-level additions.

Takeaway

The foundation is small, but it is not fake

There is already a dedicated screen, manifest path, state machine, dependency validation, source tracking, and hook surface. That is the beginning of an ecosystem, not a marketing bullet.

FAQ

Quick answers

The main confusion points are about restart behavior and load timing.

Can newly detected mods load without restarting?

No. Packages discovered after startup are marked as added at runtime and require a relaunch before they can become active.

What happens if the player has never accepted the mod warning?

The loader skips the package and leaves it disabled until the player accepts the warning flow.

Can a mod ship only art or only code?

Yes. The manifest already separates pack and DLL payloads, so a package can declare either one or both.

More V101

Related patch guides

These pages cover the other V101 additions tied to the same patch batch.