feat(progression): snapshots, ports, in-memory adapters (slice 5)
flat snapshot record per aggregate - separate files mean saving a run doesn't rewrite the Profile, deleting a slot is deleting a file, and a corrupt slot doesn't cost achievements or best times. snapshots hold primitives so Restore re-runs the value-object factories; a serialiser building LevelId directly would bypass every guard. LoadResult has three outcomes: Absent != Corrupt. Collapsing them is the bug where a version bump made ContinueGame overwrite the save. Profile.Restore writes collections directly - replaying UnlockAchievement would re-fire popups and Steam pushes on every load. 44 tests.
This commit is contained in:
26
progression/LoadResult.cs
Normal file
26
progression/LoadResult.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace Mr.BrickAdventures.Progression;
|
||||
|
||||
public enum LoadOutcome
|
||||
{
|
||||
Loaded,
|
||||
Absent,
|
||||
Corrupt,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result of loading something from a store: it was there, it was never there, or it was there
|
||||
/// and unreadable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Three outcomes rather than two, deliberately. The system being replaced collapsed "no save file"
|
||||
/// and "version mismatch" into a single <c>false</c> from <c>LoadGame</c>, which <c>ContinueGame</c>
|
||||
/// then read as "no save" — so it started a new game and overwrote the player's file. Absent means
|
||||
/// offer a new game; Corrupt means tell the player something went wrong.
|
||||
/// </remarks>
|
||||
public sealed record LoadResult<T>(LoadOutcome Outcome, T? Value, string? Problem)
|
||||
where T : class
|
||||
{
|
||||
public static LoadResult<T> Loaded(T value) => new(LoadOutcome.Loaded, value, null);
|
||||
public static LoadResult<T> Absent() => new(LoadOutcome.Absent, null, null);
|
||||
public static LoadResult<T> Corrupt(string problem) => new(LoadOutcome.Corrupt, null, problem);
|
||||
}
|
||||
Reference in New Issue
Block a user