Static helper that loads and saves HighScoreData to the game's data folder using FileSystem.Data. It returns a fresh HighScoreData on missing, unreadable, or corrupt files and logs warnings on failures. Save writes JSON and catches exceptions to avoid crashing.
namespace Coilgarden;
/// <summary>
/// Reads and writes <see cref="HighScoreData"/> to the game's data folder.
/// <para>
/// Best effort, always. A missing, unreadable or corrupt file falls back to a fresh record
/// rather than stopping the player getting into a game - losing a high score is annoying,
/// and a game that will not start because of it is worse. Every failure is logged so it is
/// not silent.
/// </para>
/// <para>
/// This class is the only thing in the project that touches the filesystem, which is why it
/// holds no logic: what counts as a new best lives in <see cref="HighScoreData"/>, where a
/// headless test can reach it.
/// </para>
/// </summary>
public static class HighScoreStore
{
public const string FileName = "coilgarden-scores.json";
public static HighScoreData Load()
{
try
{
if ( !FileSystem.Data.FileExists( FileName ) ) return new HighScoreData();
var loaded = FileSystem.Data.ReadJsonOrDefault<HighScoreData>( FileName, null );
if ( loaded is null )
{
Log.Warning( $"Coilgarden: {FileName} could not be read, starting a fresh record." );
return new HighScoreData();
}
loaded.Clamp();
return loaded;
}
catch ( Exception e )
{
Log.Warning( $"Coilgarden: {FileName} is unreadable ({e.Message}), starting a fresh record." );
return new HighScoreData();
}
}
public static void Save( HighScoreData data )
{
if ( data is null ) return;
try
{
FileSystem.Data.WriteJson( FileName, data );
}
catch ( Exception e )
{
Log.Warning( $"Coilgarden: could not save {FileName} ({e.Message})" );
}
}
}