diff --git a/GFramework.Game.Abstractions/setting/AudioSettings.cs b/GFramework.Game.Abstractions/setting/AudioSettings.cs index a0e2e2d..1f0d6af 100644 --- a/GFramework.Game.Abstractions/setting/AudioSettings.cs +++ b/GFramework.Game.Abstractions/setting/AudioSettings.cs @@ -1,4 +1,4 @@ -namespace GFramework.Game.Abstractions.setting; +namespace GFramework.Game.Abstractions.setting; /// /// 音频设置类,用于管理游戏中的音频配置 @@ -19,4 +19,14 @@ public class AudioSettings : ISettingsData /// 获取或设置音效音量,控制SFX的播放音量 /// public float SfxVolume { get; set; } = 0.8f; + + /// + /// 重置音频设置为默认值 + /// + public void Reset() + { + MasterVolume = 1.0f; + BgmVolume = 0.8f; + SfxVolume = 0.8f; + } } \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/GraphicsSettings.cs b/GFramework.Game.Abstractions/setting/GraphicsSettings.cs index e27cab8..cfd7b86 100644 --- a/GFramework.Game.Abstractions/setting/GraphicsSettings.cs +++ b/GFramework.Game.Abstractions/setting/GraphicsSettings.cs @@ -19,4 +19,14 @@ public class GraphicsSettings : ISettingsData /// 获取或设置屏幕分辨率高度 /// public int ResolutionHeight { get; set; } = 1080; + + /// + /// 重置图形设置为默认值 + /// + public void Reset() + { + Fullscreen = false; + ResolutionWidth = 1920; + ResolutionHeight = 1080; + } } \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/ISettingsData.cs b/GFramework.Game.Abstractions/setting/ISettingsData.cs index 4894bdd..dfa1a41 100644 --- a/GFramework.Game.Abstractions/setting/ISettingsData.cs +++ b/GFramework.Game.Abstractions/setting/ISettingsData.cs @@ -1,6 +1,12 @@ -namespace GFramework.Game.Abstractions.setting; +namespace GFramework.Game.Abstractions.setting; /// /// 设置数据接口 - 纯数据,可自动创建 /// -public interface ISettingsData : ISettingsSection; \ No newline at end of file +public interface ISettingsData : ISettingsSection +{ + /// + /// 重置设置为默认值 + /// + void Reset(); +} \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs b/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs index 9e3074b..569620d 100644 --- a/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs +++ b/GFramework.Game.Abstractions/setting/ISettingsPersistence.cs @@ -40,14 +40,4 @@ public interface ISettingsPersistence : IContextUtility /// 加载所有已知类型的设置数据 /// Task> LoadAllAsync(IEnumerable knownTypes); - - /// - /// 重置指定类型的设置数据为默认值 - /// - Task ResetAsync() where T : class, ISettingsData, new(); - - /// - /// 重置所有设置数据为默认值 - /// - Task ResetAllAsync(); } \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/ISettingsSystem.cs b/GFramework.Game.Abstractions/setting/ISettingsSystem.cs index 9912c84..2afb5b3 100644 --- a/GFramework.Game.Abstractions/setting/ISettingsSystem.cs +++ b/GFramework.Game.Abstractions/setting/ISettingsSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; using GFramework.Core.Abstractions.system; @@ -28,5 +28,23 @@ public interface ISettingsSystem : ISystem /// /// 批量应用多个设置类型 /// + /// 设置配置类型集合 Task Apply(IEnumerable settingsTypes); + + /// + /// 重置指定类型的设置 + /// + /// 设置类型 + Task ResetAsync(Type settingsType); + + /// + /// 重置指定类型的设置(泛型版本) + /// + /// 设置类型 + Task ResetAsync() where T : class, ISettingsData, new(); + + /// + /// 重置所有设置 + /// + Task ResetAllAsync(); } \ No newline at end of file diff --git a/GFramework.Game.Abstractions/setting/SettingsData.cs b/GFramework.Game.Abstractions/setting/SettingsData.cs new file mode 100644 index 0000000..cc8d9ae --- /dev/null +++ b/GFramework.Game.Abstractions/setting/SettingsData.cs @@ -0,0 +1,36 @@ +using System; +using System.Reflection; + +namespace GFramework.Game.Abstractions.setting; + +/// +/// 设置数据抽象基类,提供默认的 Reset() 实现 +/// +public abstract class SettingsData : ISettingsData +{ + /// + /// 重置设置为默认值 + /// 使用反射将所有属性重置为它们的默认值 + /// + public virtual void Reset() + { + var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (var prop in properties) + { + if (!prop.CanWrite || !prop.CanRead) continue; + + var defaultValue = GetDefaultValue(prop.PropertyType); + prop.SetValue(this, defaultValue); + } + } + + /// + /// 获取指定类型的默认值 + /// + /// 要获取默认值的类型 + /// 类型的默认值 + private static object? GetDefaultValue(Type type) + { + return type.IsValueType ? Activator.CreateInstance(type) : null; + } +} \ No newline at end of file diff --git a/GFramework.Game/setting/SettingsPersistence.cs b/GFramework.Game/setting/SettingsPersistence.cs index c26cea4..e777185 100644 --- a/GFramework.Game/setting/SettingsPersistence.cs +++ b/GFramework.Game/setting/SettingsPersistence.cs @@ -118,50 +118,6 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence return result; } - public async Task ResetAsync() where T : class, ISettingsData, new() - { - var type = typeof(T); - var key = GetKey(type); - - T oldSettings; - if (await _storage.ExistsAsync(key)) - { - oldSettings = await _storage.ReadAsync(key); - } - else - { - oldSettings = new T(); - } - - var newSettings = new T(); - await _storage.WriteAsync(key, newSettings); - - this.SendEvent(new SettingsResetEvent(oldSettings, newSettings)); - return newSettings; - } - - public async Task ResetAllAsync() - { - var knownTypes = new List(); - - var audioSettings = await LoadAllAsync(knownTypes); - var allNewSettings = new List(); - - foreach (var kvp in audioSettings) - { - var type = kvp.Key; - var key = GetKey(type); - - var newSettings = Activator.CreateInstance(type) as ISettingsSection; - if (newSettings is null) continue; - - await _storage.WriteAsync(key, newSettings); - allNewSettings.Add(newSettings); - } - - this.SendEvent(new SettingsResetAllEvent(allNewSettings)); - } - protected override void OnInit() { _storage = this.GetUtility()!; diff --git a/GFramework.Game/setting/SettingsSystem.cs b/GFramework.Game/setting/SettingsSystem.cs index 70ba895..7f37ea7 100644 --- a/GFramework.Game/setting/SettingsSystem.cs +++ b/GFramework.Game/setting/SettingsSystem.cs @@ -1,6 +1,7 @@ using GFramework.Core.extensions; using GFramework.Core.system; using GFramework.Game.Abstractions.setting; +using GFramework.Game.setting.commands; using GFramework.Game.setting.events; namespace GFramework.Game.setting; @@ -27,59 +28,27 @@ public class SettingsSystem : AbstractSystem, ISettingsSystem return Task.CompletedTask; } - /// - /// 应用指定类型的设置配置 - /// - /// 设置配置类型,必须是类且实现ISettingsSection接口 - /// 完成的任务 - public Task Apply() where T : class, ISettingsSection - => Apply(typeof(T)); - - /// - /// 应用指定类型的设置配置 - /// - /// 设置配置类型 - /// 完成的任务 - public Task Apply(Type settingsType) + public Task ResetAsync(Type settingsType) { - if (!_model.TryGet(settingsType, out var section)) - return Task.CompletedTask; - - TryApply(section); - return Task.CompletedTask; - } - - /// - /// 应用指定类型集合的设置配置 - /// - /// 设置配置类型集合 - /// 完成的任务 - public Task Apply(IEnumerable settingsTypes) - { - // 去重后遍历设置类型,获取并应用对应的设置配置 - foreach (var type in settingsTypes.Distinct()) + return this.SendCommandAsync(new ResetSettingsCommand(new ResetSettingsInput { - if (_model.TryGet(type, out var section)) - { - TryApply(section); - } - } - - return Task.CompletedTask; + SettingsType = settingsType + })); } - /// - /// 初始化设置系统,获取设置模型实例 - /// - protected override void OnInit() + public Task ResetAsync() where T : class, ISettingsData, new() { - _model = this.GetModel()!; + return ResetAsync(typeof(T)); + } + + public Task ResetAllAsync() + { + return this.SendCommandAsync(new ResetSettingsCommand(new ResetSettingsInput + { + SettingsType = null + })); } - /// - /// 尝试应用可应用的设置配置 - /// - /// 设置配置对象 private void TryApply(ISettingsSection section) { if (section is IApplyAbleSettings applyable) diff --git a/GFramework.Game/setting/commands/ResetSettingsCommand.cs b/GFramework.Game/setting/commands/ResetSettingsCommand.cs new file mode 100644 index 0000000..fa1c835 --- /dev/null +++ b/GFramework.Game/setting/commands/ResetSettingsCommand.cs @@ -0,0 +1,54 @@ +using GFramework.Core.command; +using GFramework.Game.Abstractions.setting; +using GFramework.Game.setting.events; + +namespace GFramework.Game.setting.commands; + +public sealed class ResetSettingsCommand : AbstractAsyncCommand +{ + private ISettingsModel _model = null!; + private ISettingsPersistence _persistence = null!; + + protected override void OnContextReady() + { + base.OnContextReady(); + _model = this.GetModel()!; + _persistence = this.GetUtility()!; + } + + protected override async Task OnExecuteAsync(ResetSettingsInput input) + { + if (input.SettingsType == null) + await ResetAll(); + else + await ResetSingle(input.SettingsType); + } + + private async Task ResetSingle(Type settingsType) + { + if (!_model.TryGet(settingsType, out var section)) + throw new InvalidOperationException($"Settings {settingsType.Name} not found"); + + if (section is not ISettingsData settingsData) + throw new InvalidOperationException($"Settings {settingsType.Name} is not ISettingsData"); + + settingsData.Reset(); + await _persistence.SaveAsync(settingsData); + this.SendEvent(new SettingsResetEvent(settingsData)); + } + + private async Task ResetAll() + { + var allSettings = _model.All() + .OfType() + .ToList(); + + foreach (var settings in allSettings) + { + settings.Reset(); + await _persistence.SaveAsync(settings); + } + + this.SendEvent(new SettingsResetAllEvent(allSettings)); + } +} \ No newline at end of file diff --git a/GFramework.Game/setting/commands/ResetSettingsInput.cs b/GFramework.Game/setting/commands/ResetSettingsInput.cs new file mode 100644 index 0000000..7200737 --- /dev/null +++ b/GFramework.Game/setting/commands/ResetSettingsInput.cs @@ -0,0 +1,8 @@ +using GFramework.Core.Abstractions.command; + +namespace GFramework.Game.setting.commands; + +public sealed class ResetSettingsInput : ICommandInput +{ + public Type? SettingsType { get; init; } +} \ No newline at end of file diff --git a/GFramework.Game/setting/events/SettingsResetEvent.cs b/GFramework.Game/setting/events/SettingsResetEvent.cs index ae4e40b..be6755c 100644 --- a/GFramework.Game/setting/events/SettingsResetEvent.cs +++ b/GFramework.Game/setting/events/SettingsResetEvent.cs @@ -6,29 +6,13 @@ namespace GFramework.Game.setting.events; /// 表示设置重置事件 /// /// 设置节类型 -public class SettingsResetEvent : ISettingsChangedEvent +public class SettingsResetEvent(T newSettings) : ISettingsChangedEvent where T : ISettingsSection { - /// - /// 构造函数 - /// - /// 重置前的设置 - /// 重置后的新设置 - public SettingsResetEvent(T oldSettings, T newSettings) - { - OldSettings = oldSettings; - NewSettings = newSettings; - } - - /// - /// 获取重置前的设置 - /// - public T OldSettings { get; } - /// /// 获取重置后的新设置 /// - public T NewSettings { get; } + public T NewSettings { get; } = newSettings; /// /// 获取类型化的设置实例(返回新设置) diff --git a/GFramework.Godot/setting/AudioBusMapSettings.cs b/GFramework.Godot/setting/AudioBusMapSettings.cs index a8c8d55..883325b 100644 --- a/GFramework.Godot/setting/AudioBusMapSettings.cs +++ b/GFramework.Godot/setting/AudioBusMapSettings.cs @@ -1,4 +1,4 @@ -using GFramework.Game.Abstractions.setting; +using GFramework.Game.Abstractions.setting; namespace GFramework.Godot.setting; @@ -25,4 +25,14 @@ public class AudioBusMapSettings : ISettingsData /// 默认值为"SFX" /// public string Sfx { get; set; } = "SFX"; + + /// + /// 重置音频总线映射设置为默认值 + /// + public void Reset() + { + Master = "Master"; + Bgm = "BGM"; + Sfx = "SFX"; + } } \ No newline at end of file