Custom campaign facts belong in the save scope whose lifetime matches the fact. The active StoryGameSession owns a SaveState, which contains regular campaign state, MiscWorldSaveData, and DeathPersistentSaveData. PlayerProgression.MiscProgressionData sits outside one campaign’s world state and holds broader progression.
SlugBase adds typed key and value access to all three scopes. It is an optional dependency for Rain World mods and is required for the extension methods on this page. The API was checked at source commit dac343359d0f6e311de9f89345954f9ad2b25f3e. Compatibility with the current SlugBase release is unverified.
Choose a scope
| Data owner | Use it for | Vanilla examples |
|---|---|---|
MiscWorldSaveData | Facts stored with the current campaign’s world state | SSaiConversationsHad, EverMetMoon, SLOracleState |
DeathPersistentSaveData | Facts that must remain after death or quitting | karma, the Mark, unlocked gates, read chatlogs |
PlayerProgression.MiscProgressionData | Facts shared through the player’s broader progression | unlocks and collection progress |
Cycle number, food, den position, regions, and object trackers live directly on SaveState. That type boundary describes the game’s storage model. It is not an invitation to add fields to game types or edit their serialized strings.
For a campaign encounter that must remain recorded after the player dies, attach the custom value to DeathPersistentSaveData. For a local world fact that should travel with ordinary world state, use MiscWorldSaveData. Use progression data only when the value genuinely applies beyond one campaign.
Read and change SlugBase data
Import SlugBase.SaveData, select the owner, and call GetSlugBaseData(). The returned SlugBaseSaveData has TryGet<T>, Set<T>, and Remove. This handler fragment requires an active story session. Keep it out of arena and menu paths:
using SlugBase.SaveData;
if (game == null || !game.IsStorySession)
return;
var data = game.GetStorySession
.saveState
.deathPersistentSaveData
.GetSlugBaseData();
data.Set("lanternwren.met_oracle", true);
bool metOracle =
data.TryGet<bool>("lanternwren.met_oracle", out var stored) && stored;Prefix keys with a stable mod or character identifier. Callers pass the plain key. SlugBase appends its own internal suffix before serializing the entry, so code should continue to use lanternwren.met_oracle for later reads and removal.
Set updates the in-memory SlugBaseSaveData dictionary. It does not flush a save to disk. Choose a gameplay event where the fact becomes true, set it there, and let Rain World’s normal save lifecycle perform the write.
Let the game save
flowchart TD A[Load campaign] --> B[Change scoped data] B --> C[Game requests a save] C --> D[SlugBase adds custom entries] D --> E[Game serializes the owner] E --> F[Write save data]
PlayerProgression.GetOrInitiateSaveState loads a matching state or initializes a new one. During a regular world save, SaveWorldStateAndProgression reaches SaveState.SaveToString(). The death and quit route calls DeathPersistentSaveData.SaveToString(saveAsIfPlayerDied, saveAsIfPlayerQuit).
SlugBase hooks DeathPersistentSaveData.SaveToString, MiscWorldSaveData.ToString, and PlayerProgression.MiscProgressionData.ToString. Before each original serializer runs, it copies the matching custom entries into that owner’s unrecognizedSaveStrings. TryGet can later deserialize a stored JSON value back to the requested type.
Do not call these serializers merely to persist one custom value, and do not rewrite Rain World’s save files from mod code. Those routes include lifecycle decisions about death, quitting, starvation, enabled mods, and the active slot. Hook lifecycle covers how to attach the gameplay event that changes the value. Oracle dialogue shows where a saved encounter fact can enter dialogue dispatch.
The snippet and lifecycle were checked against source only. No save was read, written, migrated, or recovered in the game, so this page makes no recovery or migration guarantee.
Sources
global::SaveState,global::MiscWorldSaveData,global::DeathPersistentSaveData, andglobal::PlayerProgressioninAssembly-CSharp.dll, SHA-256B6BE1D4E18CE219D21091B51564CB6A11C1E4106B41DE903EB8E58849CB16FDB. See Runtime reference.- SlugBase save data extension methods
SlugBaseSaveDatatyped access and serialization- SlugBase serializer hooks