using System; using Cielonos.MainGame.UI; using SLSUtilities.General; using SLSUtilities.UI; using SLSUtilities.WwiseAssistance; using UnityEngine; using UnityEngine.Localization.Settings; namespace Cielonos.Settings { /// /// 游戏设置的 Singleton 管理器。 /// /// 数据流:
/// 字段初始化器提供编译期默认值 → /// 中通过 ES3 加载磁盘数据覆盖 → /// 中调用 推送到各子系统。 ///
/// /// 扩展方式:直接在对应 Settings 类( /// / / /// / )中添加带默认值的新字段。 /// ES3 反序列化时,旧存档缺失的字段自动获取字段初始化器的默认值。 /// 然后在对应的 Apply 方法中添加新字段的应用逻辑即可。 /// ///
public class GameSettingsManager : Singleton { // ──────────────────────── 持久化常量 ──────────────────────── private const string SaveFileName = "GameSettings.es3"; private const string KeyGameplay = "gameplay"; private const string KeyGraphics = "graphics"; private const string KeySound = "sound"; private const string KeyControls = "controls"; // ──────────────────────── Wwise RTPC 名称 ────────────────── private const string RtpcMasterVolume = "MasterVolume"; private const string RtpcMusicVolume = "MusicVolume"; private const string RtpcSfxVolume = "SFXVolume"; // ──────────────────────── 运行时数据 ─────────────────────── public GameplaySettings gameplay = new(); public GraphicsSettings graphics = new(); public SoundSettings sound = new(); public ControlsSettings controls = new(); // ──────────────────────── 事件 ───────────────────────────── /// Gameplay 设置被应用后触发。 public static event Action OnGameplaySettingsApplied; /// Graphics 设置被应用后触发。 public static event Action OnGraphicsSettingsApplied; /// Sound 设置被应用后触发。 public static event Action OnSoundSettingsApplied; /// Controls 设置被应用后触发。 public static event Action OnControlsSettingsApplied; // ──────────────────────── 生命周期 ───────────────────────── protected override void Awake() { base.Awake(); Load(); } private void Start() { ApplyAll(); } // ──────────────────────── 持久化 ─────────────────────────── /// /// 将所有设置分类保存到磁盘。每个分类使用独立的 ES3 Key, /// 某个分类数据损坏时不影响其他分类。 /// public void Save() { try { ES3.Save(KeyGameplay, gameplay, SaveFileName); ES3.Save(KeyGraphics, graphics, SaveFileName); ES3.Save(KeySound, sound, SaveFileName); ES3.Save(KeyControls, controls, SaveFileName); Debug.Log("[GameSettingsManager] Settings saved."); } catch (Exception e) { Debug.LogError($"[GameSettingsManager] Save failed: {e.Message}"); } } /// /// 从磁盘加载设置。每个分类独立加载,某个分类缺失或损坏时 /// 保留字段初始化器的默认值。 /// public void Load() { try { if (!ES3.FileExists(SaveFileName)) return; if (ES3.KeyExists(KeyGameplay, SaveFileName)) gameplay = ES3.Load(KeyGameplay, SaveFileName); if (ES3.KeyExists(KeyGraphics, SaveFileName)) graphics = ES3.Load(KeyGraphics, SaveFileName); if (ES3.KeyExists(KeySound, SaveFileName)) sound = ES3.Load(KeySound, SaveFileName); if (ES3.KeyExists(KeyControls, SaveFileName)) controls = ES3.Load(KeyControls, SaveFileName); } catch (Exception e) { Debug.LogError($"[GameSettingsManager] Load failed: {e.Message}"); } } /// /// 删除设置存档文件。 /// public void DeleteSaveFile() { try { if (ES3.FileExists(SaveFileName)) { ES3.DeleteFile(SaveFileName); Debug.Log("[GameSettingsManager] Save file deleted."); } } catch (Exception e) { Debug.LogError($"[GameSettingsManager] Delete save failed: {e.Message}"); } } // ──────────────────────── Apply ──────────────────────────── /// /// 应用所有分类的设置到对应系统。 /// public void ApplyAll() { ApplyGameplay(); ApplyGraphics(); ApplySound(); ApplyControls(); } /// /// 应用 Gameplay 设置。 /// public void ApplyGameplay() { // Locale var availableLocales = LocalizationSettings.AvailableLocales; if (availableLocales != null) { var locale = availableLocales.GetLocale(gameplay.locale); if (locale != null) LocalizationSettings.SelectedLocale = locale; } // FPS 显示 if (PlayerCanvas.Instance != null) PlayerCanvas.Instance.frameRateText.gameObject.SetActive(gameplay.showFPS); OnGameplaySettingsApplied?.Invoke(); } /// /// 应用 Graphics 设置。 /// public void ApplyGraphics() { // 分辨率与全屏模式 if (graphics.resolutionWidth > 0 && graphics.resolutionHeight > 0) { Screen.SetResolution( graphics.resolutionWidth, graphics.resolutionHeight, graphics.fullscreenMode ); } else { Screen.fullScreenMode = graphics.fullscreenMode; } // 画质预设 if (graphics.qualityLevel >= 0) QualitySettings.SetQualityLevel(graphics.qualityLevel, applyExpensiveChanges: true); // VSync QualitySettings.vSyncCount = graphics.vSync ? 1 : 0; // 帧率上限 Application.targetFrameRate = graphics.targetFrameRate; OnGraphicsSettingsApplied?.Invoke(); } /// /// 应用 Sound 设置(通过 Wwise RTPC)。 /// public void ApplySound() { if (AudioManager.Instance == null) return; AudioManager.Instance.SetRTPC(RtpcMasterVolume, sound.masterVolume); AudioManager.Instance.SetRTPC(RtpcMusicVolume, sound.musicVolume); AudioManager.Instance.SetRTPC(RtpcSfxVolume, sound.sfxVolume); OnSoundSettingsApplied?.Invoke(); } /// /// 应用 Controls 设置。 /// /// 按键绑定覆盖由 PlayerInputSubcontroller 消费: /// 在其 Initialize() 中读取 . /// 并调用 InputActionAsset.LoadBindingOverridesFromJson(), /// 然后重新初始化 。 /// /// public void ApplyControls() { OnControlsSettingsApplied?.Invoke(); } // ──────────────────────── Reset ──────────────────────────── /// /// 重置所有设置为默认值并立即应用。 /// public void ResetAllToDefault() { gameplay = new GameplaySettings(); graphics = new GraphicsSettings(); sound = new SoundSettings(); controls = new ControlsSettings(); ApplyAll(); } /// /// 重置 Gameplay 设置为默认值并立即应用。 /// public void ResetGameplayToDefault() { gameplay = new GameplaySettings(); ApplyGameplay(); } /// /// 重置 Graphics 设置为默认值并立即应用。 /// public void ResetGraphicsToDefault() { graphics = new GraphicsSettings(); ApplyGraphics(); } /// /// 重置 Sound 设置为默认值并立即应用。 /// public void ResetSoundToDefault() { sound = new SoundSettings(); ApplySound(); } /// /// 重置 Controls 设置为默认值并立即应用。 /// public void ResetControlsToDefault() { controls = new ControlsSettings(); ApplyControls(); } } }