GFramework/GFramework.Game/setting/SettingsPersistence.cs
GeWuYou 442e8e7088 refactor(setting): 重构设置系统以支持数据和应用器分离
- 将SettingsModel内部存储分离为_dataSettings和_applicators两个字典
- 添加IDataSettings接口用于标识纯数据设置
- 修改Get方法为GetData以明确区分数据获取
- 添加RegisterApplicator和GetApplicator方法管理可应用设置
- 更新TryGet方法支持从数据和应用器中查找设置
- 扩展SettingsPersistence支持批量保存和加载所有设置数据
- 将AudioBusMap重命名为AudioBusMapSettings并实现ISettingsData接口
- 修改Godot音频和图形设置适配新的接口变更
- [skip ci]
2026-01-16 23:44:28 +08:00

128 lines
4.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Abstractions.storage;
using GFramework.Core.extensions;
using GFramework.Core.utility;
using GFramework.Game.Abstractions.setting;
namespace GFramework.Game.setting;
/// <summary>
/// 设置持久化服务类,负责处理设置数据的加载、保存、删除等操作
/// </summary>
public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence
{
private IStorage _storage = null!;
/// <summary>
/// 异步加载指定类型的设置数据
/// </summary>
/// <typeparam name="T">设置数据类型必须实现ISettingsData接口</typeparam>
/// <returns>如果存在则返回存储的设置数据,否则返回新创建的实例</returns>
public async Task<T> LoadAsync<T>() where T : class, ISettingsData, new()
{
var key = GetKey<T>();
if (await _storage.ExistsAsync(key))
{
return await _storage.ReadAsync<T>(key);
}
return new T();
}
/// <summary>
/// 异步保存设置数据到存储中
/// </summary>
/// <typeparam name="T">设置数据类型必须实现ISettingsData接口</typeparam>
/// <param name="section">要保存的设置数据实例</param>
public async Task SaveAsync<T>(T section) where T : class, ISettingsData
{
var key = GetKey<T>();
await _storage.WriteAsync(key, section);
}
/// <summary>
/// 检查指定类型的设置数据是否存在
/// </summary>
/// <typeparam name="T">设置数据类型必须实现ISettingsData接口</typeparam>
/// <returns>如果存在返回true否则返回false</returns>
public async Task<bool> ExistsAsync<T>() where T : class, ISettingsData
{
var key = GetKey<T>();
return await _storage.ExistsAsync(key);
}
/// <summary>
/// 异步删除指定类型的设置数据
/// </summary>
/// <typeparam name="T">设置数据类型必须实现ISettingsData接口</typeparam>
public async Task DeleteAsync<T>() where T : class, ISettingsData
{
var key = GetKey<T>();
_storage.Delete(key);
await Task.CompletedTask;
}
/// <summary>
/// 异步保存所有设置数据到存储中
/// </summary>
/// <param name="allData">包含所有设置数据的可枚举集合</param>
public async Task SaveAllAsync(IEnumerable<ISettingsData> allData)
{
foreach (var data in allData)
{
var type = data.GetType();
var key = GetKey(type);
await _storage.WriteAsync(key, data);
}
}
/// <summary>
/// 异步加载所有已知类型的设置数据
/// </summary>
/// <param name="knownTypes">已知设置数据类型的集合</param>
/// <returns>类型与对应设置数据的字典映射</returns>
public async Task<IDictionary<Type, ISettingsData>> LoadAllAsync(IEnumerable<Type> knownTypes)
{
var result = new Dictionary<Type, ISettingsData>();
foreach (var type in knownTypes)
{
var key = GetKey(type);
if (!await _storage.ExistsAsync(key)) continue;
// 使用反射调用泛型方法
var method = typeof(IStorage)
.GetMethod(nameof(IStorage.ReadAsync))!
.MakeGenericMethod(type);
var task = (Task)method.Invoke(_storage, [key])!;
await task;
var loaded = (ISettingsData)((dynamic)task).Result;
result[type] = loaded;
}
return result;
}
protected override void OnInit()
{
_storage = this.GetUtility<IStorage>()!;
}
/// <summary>
/// 获取指定类型的存储键名
/// </summary>
/// <typeparam name="T">设置数据类型</typeparam>
/// <returns>格式为"Settings_类型名称"的键名</returns>
private static string GetKey<T>() where T : ISettingsData
=> GetKey(typeof(T));
/// <summary>
/// 获取指定类型的存储键名
/// </summary>
/// <param name="type">设置数据类型</param>
/// <returns>格式为"Settings_类型名称"的键名</returns>
private static string GetKey(Type type)
=> $"Settings_{type.Name}";
}