Store data in the save
Problem. Your mod has settings or state that should travel with the player's save.
Solution. ModSaveDataExtensions attaches a serialisable class of yours to the
savegame. You never touch serialisation code.
Attach it
using ShapezShifter.Flow;
public class MySaveData
{
public bool OverlayEnabled = true;
public int ColorScheme;
}
public MyMod(ILogger logger)
{
this.AttachSaveData<MySaveData>(); // needs a parameterless constructor
}
With non-default initial values:
this.AttachSaveData(() => new MySaveData { OverlayEnabled = false });
Attach in the constructor. It has to be registered before a save is loaded, or there is nothing to deserialise into.
Read and write it
MySaveData data = this.GetSaveData<MySaveData>();
data.OverlayEnabled = !data.OverlayEnabled; // mutate in place; it is your object
The full surface:
void AttachSaveData<T>() // and Func<T> / IFactory<T> overloads
T GetSaveData<T>()
void ResetSaveDataToDefault<T>()
void DetachSaveData<T>()
void RegisterToBeforeSaveDataSerialized<T>(Action<T>)
void RegisterToAfterSaveDataDeserialized<T>(Action<T>)
void UnregisterToBeforeSaveDataSerialized<T>(Action<T>)
void UnregisterToAfterSaveDataDeserialized<T>(Action<T>)
The two lifecycle hooks
// Flush live state into the object just before it is written:
this.RegisterToBeforeSaveDataSerialized<MySaveData>(data => data.OverlayEnabled = Enabled);
// Apply loaded values once the save has been read:
this.RegisterToAfterSaveDataDeserialized<MySaveData>(data => Enabled = data.OverlayEnabled);
AfterSaveDataDeserialized is also a clean answer to "when has a game loaded?" for
anything that only depends on your own data — it fires with the values already
populated. For anything touching the map, still use the map check in
Run code when a game loads.
Say so in the manifest
"AffectsSaveGames": true,
"SavedModVersionCompabilityRangeWithSelf": "<1.1.0"
AffectsSaveGames marks saves as depending on your mod. SavedModVersionCompabilityRangeWithSelf
(the typo is the game's) declares which versions of your own mod can read data written
by this one — tighten it whenever you change your data class incompatibly.
An overlay that only reads and draws needs none of this; it should set
AffectsSaveGames: false and keep settings in a config file instead, so players can
share saves freely.
Gotchas
- Data is stored per save. Global preferences belong in your own file under the mod
folder (
ModDirectoryLocator/ModFolderLocatorfind it). - Adding or removing fields between versions is a compatibility decision. Old saves deserialise into the new shape, so give new fields sensible defaults and never assume a field was written.
GetSaveData<T>before anything is attached or loaded will not give you a useful object — attach in the constructor and read after load.