Files
TheriapolisV3/Theriapolis.Core/Persistence/SaveHeader.cs
T
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:40:51 -07:00

57 lines
1.9 KiB
C#

using System.Text.Json.Serialization;
namespace Theriapolis.Core.Persistence;
/// <summary>
/// JSON-serializable metadata stored at the front of a save file. Designed so
/// the slot picker can deserialize just the header (with a 4-byte length
/// prefix preceding it) without touching the binary body.
/// </summary>
public sealed class SaveHeader
{
/// <summary>Schema version. Bump on breaking changes — see SaveMigrations.</summary>
[JsonPropertyName("version")]
public int Version { get; set; } = C.SAVE_SCHEMA_VERSION;
[JsonPropertyName("worldSeed")]
public string WorldSeedHex { get; set; } = "0x0";
[JsonPropertyName("stageHashes")]
public Dictionary<string, string> StageHashes { get; set; } = new();
[JsonPropertyName("playerName")]
public string PlayerName { get; set; } = "Wanderer";
[JsonPropertyName("playerTier")]
public int PlayerTier { get; set; }
[JsonPropertyName("inGameSeconds")]
public long InGameSeconds { get; set; }
[JsonPropertyName("savedAt")]
public string SavedAtUtc { get; set; } = "";
[JsonPropertyName("appVersion")]
public string AppVersion { get; set; } = "0.4.0";
/// <summary>Convenience: a one-line label for the slot picker.</summary>
public string SlotLabel()
{
// "Wanderer — Y0 Spring D5 (Tier 1)" style
long sec = InGameSeconds;
long days = sec / Time.WorldClock.SecondsPerDay;
int year = (int)(days / Time.WorldClock.DaysPerYear);
var season = (Time.Season)((days / Time.WorldClock.DaysPerSeason) % 4);
long dayOfSeason = days % Time.WorldClock.DaysPerSeason;
return $"{PlayerName} — Y{year} {season} D{dayOfSeason} (Tier {PlayerTier})";
}
public ulong ParseSeed()
{
string s = WorldSeedHex.Trim();
if (s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
return Convert.ToUInt64(s[2..], 16);
return ulong.Parse(s);
}
}