Editor helper that reads and writes local JSON settings files for the Advanced Mapping Tools addon. Read deserializes a file and logs a warning on failure, Write writes to a temp file, backs up a corrupt previous file, then replaces the original.
namespace AdvancedMappingTools;
/// <summary>Read damaged local settings without taking the editor UI down; preserve them on the next save.</summary>
internal static class StoreSafety
{
static readonly Dictionary<string, DateTime> Reported = [];
internal static void Warn( string path, string problem )
{
DateTime stamp;
try
{
stamp = System.IO.File.GetLastWriteTimeUtc( path );
}
catch
{
stamp = DateTime.MinValue;
}
if ( Reported.TryGetValue( path, out var previous ) && previous == stamp )
return;
Reported[path] = stamp;
Log.Warning( $"AMT settings: {System.IO.Path.GetFileName( path )} could not be used: {problem}. The original file was kept." );
}
internal static T Read<T>( string path )
{
if ( !System.IO.File.Exists( path ) )
return default;
try
{
return System.Text.Json.JsonSerializer.Deserialize<T>( System.IO.File.ReadAllText( path ) );
}
catch ( Exception ex )when ( ex is System.Text.Json.JsonException or System.IO.IOException or UnauthorizedAccessException )
{
Warn( path, ex.Message );
return default;
}
}
internal static void Write( string path, string json )
{
System.IO.Directory.CreateDirectory( System.IO.Path.GetDirectoryName( path ) );
var temporary = path + "." + Guid.NewGuid().ToString( "N" ) + ".tmp";
try
{
System.IO.File.WriteAllText( temporary, json );
if ( System.IO.File.Exists( path ) )
{
try
{
using var previous = System.Text.Json.JsonDocument.Parse( System.IO.File.ReadAllText( path ) );
}
catch ( System.Text.Json.JsonException )
{
var recovery = path + ".corrupt_" + DateTime.UtcNow.ToString( "yyyyMMdd_HHmmss" ) + "_" + Guid.NewGuid().ToString( "N" );
System.IO.File.Copy( path, recovery, false );
Log.Warning( $"AMT settings: the damaged previous file was preserved as {System.IO.Path.GetFileName( recovery )}." );
}
System.IO.File.Replace( temporary, path, null );
}
else
System.IO.File.Move( temporary, path );
Reported.Remove( path );
}
finally
{
if ( System.IO.File.Exists( temporary ) )
System.IO.File.Delete( temporary );
}
}
}