# 设置系统 设置系统负责管理 `ISettingsData`、持久化加载/保存,以及把设置真正应用到运行时环境。 当前实现以 `SettingsModel` 和 `SettingsSystem` 为核心,已经不是旧文档中的 `Get() / Register(IApplyAbleSettings)` 接口模型。 ## 核心概念 ### ISettingsData 设置数据对象负责保存设置值、提供默认值,并在加载后把外部数据回填到当前实例。 ```csharp public interface ISettingsData : IResettable, IVersionedData, ILoadableFrom; ``` 这意味着一个设置数据类型通常需要实现: - `Reset()`:恢复默认值 - `Version` / `LastModified`:暴露版本化信息 - `LoadFrom(ISettingsData)`:把已加载或迁移后的数据复制到当前实例 ### IResetApplyAbleSettings 应用器负责把设置数据作用到引擎或运行时环境: ```csharp public interface IResetApplyAbleSettings : IResettable, IApplyAbleSettings { ISettingsData Data { get; } Type DataType { get; } } ``` 常见用途包括: - 把音量设置同步到音频总线 - 把图形设置同步到窗口系统 - 把语言设置同步到本地化管理器 ## ISettingsModel 当前 `ISettingsModel` 的主要 API 如下: ```csharp public interface ISettingsModel : IModel { bool IsInitialized { get; } T GetData() where T : class, ISettingsData, new(); IEnumerable AllData(); ISettingsModel RegisterApplicator(T applicator) where T : class, IResetApplyAbleSettings; T? GetApplicator() where T : class, IResetApplyAbleSettings; IEnumerable AllApplicators(); ISettingsModel RegisterMigration(ISettingsMigration migration); Task InitializeAsync(); Task SaveAllAsync(); Task ApplyAllAsync(); void Reset() where T : class, ISettingsData, new(); void ResetAll(); } ``` 行为说明: - `GetData()` 返回某个设置数据的唯一实例 - `RegisterApplicator()` 注册应用器,并把其 `Data` 纳入模型管理 - `InitializeAsync()` 从 `ISettingsDataRepository` 读取所有已注册设置,并在需要时执行迁移 - `SaveAllAsync()` 持久化当前所有设置数据 - `ApplyAllAsync()` 依次调用所有 applicator 的 `Apply()` ## SettingsSystem `SettingsSystem` 是对模型的系统级封装,面向业务代码提供更直接的入口: ```csharp public interface ISettingsSystem : ISystem { Task ApplyAll(); Task Apply() where T : class, IResetApplyAbleSettings; Task SaveAll(); Task Reset() where T : class, ISettingsData, IResetApplyAbleSettings, new(); Task ResetAll(); } ``` 它不会自己保存数据,而是把保存、重置和应用逻辑委托给 `ISettingsModel`。 ## 基本用法 ### 定义设置数据 ```csharp public sealed class GameplaySettings : ISettingsData { public float GameSpeed { get; set; } = 1.0f; public int Version { get; private set; } = 1; public DateTime LastModified { get; } = DateTime.UtcNow; public void Reset() { GameSpeed = 1.0f; } public void LoadFrom(ISettingsData source) { if (source is not GameplaySettings settings) { return; } GameSpeed = settings.GameSpeed; Version = settings.Version; } } ``` ### 定义 applicator ```csharp public sealed class GameplaySettingsApplicator : IResetApplyAbleSettings { public GameplaySettingsApplicator(GameplaySettings data) { Data = data; } public ISettingsData Data { get; } public Type DataType => typeof(GameplaySettings); public void Reset() { Data.Reset(); } public Task Apply() { var settings = (GameplaySettings)Data; TimeScale.Current = settings.GameSpeed; return Task.CompletedTask; } } ``` ### 使用模型和系统 ```csharp var settingsModel = this.GetModel(); var gameplayData = settingsModel.GetData(); gameplayData.GameSpeed = 1.25f; settingsModel.RegisterApplicator(new GameplaySettingsApplicator(gameplayData)); await settingsModel.InitializeAsync(); await settingsModel.SaveAllAsync(); var settingsSystem = this.GetSystem(); await settingsSystem.ApplyAll(); ``` ## 迁移 设置系统内建了迁移注册入口: ```csharp public interface ISettingsMigration { Type SettingsType { get; } int FromVersion { get; } int ToVersion { get; } ISettingsSection Migrate(ISettingsSection oldData); } ``` 当 `InitializeAsync()` 读取到旧版本设置时,会按已注册迁移链逐步升级,再通过 `LoadFrom` 回填到当前实例。 ## 依赖项 要让设置系统完整工作,通常需要准备: - `ISettingsDataRepository` - `IDataLocationProvider` - 一个具体的存储实现和序列化器 如果使用 `UnifiedSettingsDataRepository`,多个设置节会被合并到单个设置文件中统一保存。 ## 当前边界 - 设置迁移是内建能力 - 设置持久化是内建能力 - 设置如何应用到具体引擎由 applicator 决定 - 存档系统的迁移能力不等同于设置系统;`ISaveRepository` 当前仍需要业务层自己实现迁移策略