using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.Service.Interface;
using OpenCvSharp;
using System;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
namespace BetterGenshinImpact.Service;
public class ConfigService : IConfigService
{
private readonly object _locker = new(); // 只有UI线程会调用这个方法,lock好像意义不大,而且浪费了下面的读写锁hhh
private readonly ReaderWriterLockSlim _rwLock = new();
public static readonly JsonSerializerOptions JsonOptions = new()
{
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters =
{
new OpenCvPointJsonConverter(),
new OpenCvRectJsonConverter(),
},
WriteIndented = true,
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
};
///
/// 写入只有UI线程会调用
/// 多线程只会读,放心用static,不会丢失数据
///
public static AllConfig? Config { get; private set; }
public AllConfig Get()
{
lock (_locker)
{
if (Config == null)
{
Config = Read();
Config.OnAnyChangedAction = Save; // 略微影响性能
Config.InitEvent();
}
return Config;
}
}
public void Save()
{
if (Config != null)
{
Write(Config);
}
}
public AllConfig Read()
{
_rwLock.EnterReadLock();
try
{
var filePath = Global.Absolute(@"User/config.json");
if (!File.Exists(filePath))
{
return new AllConfig();
}
var json = File.ReadAllText(filePath);
var config = JsonSerializer.Deserialize(json, JsonOptions);
if (config == null)
{
return new AllConfig();
}
Config = config;
return config;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
return new AllConfig();
}
finally
{
_rwLock.ExitReadLock();
}
}
public void Write(AllConfig config)
{
_rwLock.EnterWriteLock();
try
{
var path = Global.Absolute("User");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
var file = Path.Combine(path, "config.json");
File.WriteAllText(file, JsonSerializer.Serialize(config, JsonOptions));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
finally
{
_rwLock.ExitWriteLock();
}
}
}
public class OpenCvRectJsonConverter : JsonConverter
{
public override unsafe Rect Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
RectHelper helper = JsonSerializer.Deserialize(ref reader, options);
return *(Rect*)&helper;
}
public override unsafe void Write(Utf8JsonWriter writer, Rect value, JsonSerializerOptions options)
{
RectHelper helper = *(RectHelper*)&value;
JsonSerializer.Serialize(writer, helper, options);
}
// DO NOT MODIFY: Keep the layout same as OpenCvSharp.Rect
private struct RectHelper
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
}
public class OpenCvPointJsonConverter : JsonConverter
{
public override unsafe Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
PointHelper helper = JsonSerializer.Deserialize(ref reader, options);
return *(Point*)&helper;
}
public override unsafe void Write(Utf8JsonWriter writer, Point value, JsonSerializerOptions options)
{
PointHelper helper = *(PointHelper*)&value;
JsonSerializer.Serialize(writer, helper, options);
}
// DO NOT MODIFY: Keep the layout same as OpenCvSharp.Point
private struct PointHelper
{
public int X { get; set; }
public int Y { get; set; }
}
}