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>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user