using System.Collections.Concurrent;
using GFramework.Core.Abstractions.logging;
using GFramework.Core.extensions;
using GFramework.Core.logging;
using GFramework.Core.model;
using GFramework.Game.Abstractions.data;
using GFramework.Game.Abstractions.setting;
namespace GFramework.Game.setting;
///
/// 设置模型:
/// - 管理 Settings Data 的生命周期(Load / Save / Reset / Migration)
/// - 编排 Settings Applicator 的 Apply 行为
///
public class SettingsModel(IDataLocationProvider? locationProvider, TRepository? repository)
: AbstractModel, ISettingsModel
where TRepository : class, ISettingsDataRepository
{
private static readonly ILogger Log =
LoggerFactoryResolver.Provider.CreateLogger(nameof(SettingsModel));
private readonly ConcurrentDictionary _applicators = new();
// =========================
// Fields
// =========================
private readonly ConcurrentDictionary _data = new();
private readonly ConcurrentDictionary> _migrationCache = new();
private readonly ConcurrentDictionary<(Type type, int from), ISettingsMigration> _migrations = new();
private IDataLocationProvider? _locationProvider = locationProvider;
private ISettingsDataRepository? _repository = repository;
private ISettingsDataRepository DataRepository =>
_repository ?? throw new InvalidOperationException("ISettingsDataRepository not initialized.");
private IDataLocationProvider LocationProvider =>
_locationProvider ?? throw new InvalidOperationException("IDataLocationProvider not initialized.");
// =========================
// Data access
// =========================
///
/// 获取指定类型的设置数据实例(唯一实例)
///
public T GetData() where T : class, ISettingsData, new()
{
return (T)_data.GetOrAdd(typeof(T), _ => new T());
}
public IEnumerable AllData()
{
return _data.Values;
}
// =========================
// Applicator
// =========================
///
/// 注册设置应用器
///
public ISettingsModel RegisterApplicator(T applicator)
where T : class, IResetApplyAbleSettings
{
_applicators[typeof(T)] = applicator;
return this;
}
///
/// 获取所有设置应用器
///
public IEnumerable AllApplicators()
{
return _applicators.Values;
}
// =========================
// Migration
// =========================
public ISettingsModel RegisterMigration(ISettingsMigration migration)
{
_migrations[(migration.SettingsType, migration.FromVersion)] = migration;
return this;
}
// =========================
// Lifecycle
// =========================
///
/// 初始化设置模型:
/// - 加载所有已存在的 Settings Data
/// - 执行必要的迁移
///
public async Task InitializeAsync()
{
IDictionary allData;
try
{
allData = await DataRepository.LoadAllAsync();
}
catch (Exception ex)
{
Log.Error("Failed to load unified settings file.", ex);
return;
}
foreach (var data in _data.Values)
{
try
{
var type = data.GetType();
var location = LocationProvider.GetLocation(type);
if (!allData.TryGetValue(location.Key, out var raw))
continue;
if (raw is not ISettingsData loaded)
continue;
var migrated = MigrateIfNeeded(loaded);
// 回填(不替换实例)
data.LoadFrom(migrated);
}
catch (Exception ex)
{
Log.Error($"Failed to initialize settings data: {data.GetType().Name}", ex);
}
}
}
///
/// 将所有 Settings Data 持久化
///
public async Task SaveAllAsync()
{
foreach (var data in _data.Values)
{
try
{
var location = LocationProvider.GetLocation(data.GetType());
await DataRepository.SaveAsync(location, data);
}
catch (Exception ex)
{
Log.Error($"Failed to save settings data: {data.GetType().Name}", ex);
}
}
}
///
/// 应用所有设置
///
public async Task ApplyAllAsync()
{
foreach (var applicator in _applicators)
{
try
{
await applicator.Value.Apply();
}
catch (Exception ex)
{
Log.Error($"Failed to apply settings: {applicator.GetType().Name}", ex);
}
}
}
///
/// 重置指定类型的可重置对象
///
/// 要重置的对象类型,必须是class类型,实现IResettable接口,并具有无参构造函数
public void Reset() where T : class, ISettingsData, new()
{
var data = GetData();
data.Reset();
}
///
/// 重置所有设置
///
public void ResetAll()
{
foreach (var data in _data.Values)
data.Reset();
foreach (var applicator in _applicators)
applicator.Value.Reset();
}
///
/// 获取指定类型的设置应用器
///
/// 要获取的设置应用器类型,必须继承自IResetApplyAbleSettings
/// 设置应用器实例,如果不存在则返回null
public T? GetApplicator() where T : class, IResetApplyAbleSettings
{
return _applicators.TryGetValue(typeof(T), out var app)
? (T)app
: null;
}
// =========================
// Init
// =========================
protected override void OnInit()
{
_repository ??= this.GetUtility()!;
_locationProvider ??= this.GetUtility()!;
}
private ISettingsData MigrateIfNeeded(ISettingsData data)
{
if (data is not IVersionedData versioned)
return data;
var type = data.GetType();
var current = data;
if (!_migrationCache.TryGetValue(type, out var versionMap))
{
versionMap = _migrations
.Where(kv => kv.Key.type == type)
.ToDictionary(kv => kv.Key.from, kv => kv.Value);
_migrationCache[type] = versionMap;
}
while (versionMap.TryGetValue(versioned.Version, out var migration))
{
current = (ISettingsData)migration.Migrate(current);
versioned = current;
}
return current;
}
}