using System.Collections.Concurrent;
using GFramework.Core.Abstractions.logging;
using GFramework.Core.Abstractions.versioning;
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;
///
/// 设置模型类,用于管理不同类型的应用程序设置部分
///
public class SettingsModel(IDataRepository? repository)
: AbstractModel, ISettingsModel where TRepository : class, IDataRepository
{
private static readonly ILogger Log =
LoggerFactoryResolver.Provider.CreateLogger(nameof(SettingsModel));
private readonly ConcurrentDictionary _applicators = new();
private readonly ConcurrentDictionary _dataSettings = new();
private readonly ConcurrentDictionary> _migrationCache = new();
private readonly ConcurrentDictionary<(Type type, int from), ISettingsMigration> _migrations = new();
private IDataRepository? _repository = repository;
private IDataRepository Repository => _repository ?? throw new InvalidOperationException("Repository is not set");
// -----------------------------
// Data
// -----------------------------
///
/// 获取指定类型的设置数据实例,如果不存在则创建新的实例
///
/// 设置数据类型,必须实现ISettingsData接口并提供无参构造函数
/// 指定类型的设置数据实例
public T GetData() where T : class, IResettable, new()
{
return (T)_dataSettings.GetOrAdd(typeof(T), _ => new T());
}
///
/// 获取所有设置数据的枚举集合
///
/// 所有设置数据的枚举集合
public IEnumerable AllData()
=> _dataSettings.Values;
// -----------------------------
// Applicator
// -----------------------------
///
/// 获取所有设置应用器的枚举集合
///
/// 所有设置应用器的枚举集合
public IEnumerable AllApplicators()
=> _applicators.Values;
///
/// 注册设置应用器到模型中
///
/// 设置应用器类型,必须实现IApplyAbleSettings接口
/// 要注册的设置应用器实例
/// 当前设置模型实例,支持链式调用
public ISettingsModel RegisterApplicator(T applicator)
where T : class, IApplyAbleSettings
{
_applicators[typeof(T)] = applicator;
return this;
}
///
/// 获取指定类型的设置应用器实例
///
/// 设置应用器类型,必须实现IApplyAbleSettings接口
/// 指定类型的设置应用器实例,如果不存在则返回null
public T? GetApplicator() where T : class, IApplyAbleSettings
{
return _applicators.TryGetValue(typeof(T), out var app)
? (T)app
: null;
}
// -----------------------------
// Section lookup
// -----------------------------
///
/// 尝试获取指定类型的设置节
///
/// 要查找的设置类型
/// 输出参数,找到的设置节实例
/// 如果找到对应类型的设置节则返回true,否则返回false
public bool TryGet(Type type, out ISettingsSection section)
{
if (_dataSettings.TryGetValue(type, out var data))
{
section = data;
return true;
}
if (_applicators.TryGetValue(type, out var applicator))
{
section = applicator;
return true;
}
section = null!;
return false;
}
// -----------------------------
// Migration
// -----------------------------
///
/// 注册设置迁移器到模型中
///
/// 要注册的设置迁移器实例
/// 当前设置模型实例,支持链式调用
public ISettingsModel RegisterMigration(ISettingsMigration migration)
{
_migrations[(migration.SettingsType, migration.FromVersion)] = migration;
return this;
}
///
/// 如果需要的话,对设置节进行版本迁移
///
/// 待检查和迁移的设置节
/// 迁移后的设置节
private ISettingsSection MigrateIfNeeded(ISettingsSection section)
{
if (section is not IVersioned versioned)
return section;
var type = section.GetType();
var current = section;
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 = migration.Migrate(current);
versioned = (IVersioned)current;
}
return current;
}
// -----------------------------
// Load / Init
// -----------------------------
///
/// 异步初始化设置模型,加载指定类型的设置数据
///
/// 要初始化的设置类型数组
public async Task InitializeAsync(params Type[] settingTypes)
{
foreach (var type in settingTypes)
{
if (!typeof(IResettable).IsAssignableFrom(type) ||
!typeof(IData).IsAssignableFrom(type))
continue;
try
{
var loaded = (ISettingsSection)await Repository.LoadAsync(type);
var migrated = MigrateIfNeeded(loaded);
_dataSettings[type] = (IResettable)migrated;
_migrationCache.TryRemove(type, out _);
}
catch (Exception ex)
{
Log.Error($"Failed to load settings for {type.Name}", ex);
}
}
}
///
/// 初始化方法,用于获取设置持久化服务
///
protected override void OnInit()
{
_repository ??= this.GetUtility()!;
}
}