/* * @Author: 白哉 * @Description: * @Date: 2025年07月24日 星期四 11:07:37 * @Modify: */ using System; using System.Collections.Generic; using System.IO; using System.Linq; using ExcelConfig; using Logic.Config; using Logic.CrashSight; using Logic.Multilingual; using TH1_Logic.Tools; using UnityEngine; namespace TH1_Logic.Config { public class ConfigManager { public static ConfigManager Instance = new ConfigManager(); public GameConfig Config; public VersionConfig VersionCfg; private static ColorConfig _colorConfig; public static ColorConfig ColorConfig { get { if (_colorConfig == null) { _colorConfig = Resources.Load("TH1Config/ColorConfig"); } return _colorConfig; } } public void Init() { if (Config == null) { string path = Application.persistentDataPath + "/../Config/game_cfg.json"; string backupPath = path + ".bak"; // 尝试读取主文件 Config = TryReadGameConfig(path); // 主文件损坏,尝试从备份恢复 if (Config == null && File.Exists(backupPath)) { LogSystem.LogInfo("[ConfigManager] 主文件损坏,尝试从备份恢复..."); Config = TryReadGameConfig(backupPath); if (Config != null) { LogSystem.LogInfo("[ConfigManager] 从备份恢复成功"); try { string json = JsonUtility.ToJson(Config); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json); FileTools.SafeWriteFile(path, bytes); } catch (Exception e) { LogSystem.LogError($"[ConfigManager] 恢复写入主文件失败: {e.Message}"); } } else { LogSystem.LogError("[ConfigManager] 备份文件也已损坏,将重置数据"); } } Config ??= new GameConfig(); // 老存档兜底:旧版本 GameConfig 没有 SecondaryLanguage 字段, // JsonUtility 反序列化得到默认值 None,此处刷新为 EN。 if (Config.SecondaryLanguage == MultilingualType.None) { Config.SecondaryLanguage = MultilingualType.EN; } } if (!VersionCfg) { VersionCfg = Resources.Load("Export/VersionConfig"); } CrashSightAgent.SetAppVersion(VersionCfg.CurVersionInfo.FullVersion); } public void InitExcelConfig() { // 获取当前程序集中所有实现 IExcelConfig 接口的类 var excelConfigTypes = System.Reflection.Assembly.GetExecutingAssembly().GetTypes() .Where(t => typeof(ExcelConfigBase).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract); foreach (var type in excelConfigTypes) { try { // 创建实例 var instance = (ExcelConfigBase)Activator.CreateInstance(type); // 这里可以根据需要加载对应的配置数据 // 例如:从 Resources 或其他路径加载 byte[] 数据 byte[] configData = LoadConfigData(type.Name); // 调用 Init 方法 instance.Init(configData); instance.AfterInit(); } catch (Exception ex) { LogSystem.LogError($"初始化配置失败: {type.Name}, 错误: {ex.Message}"); } } } private byte[] LoadConfigData(string typeName) { string configName = typeName.Replace("Category", ""); TextAsset asset = Resources.Load($"ExcelConfig/GenerateBytes/{configName}"); if (asset == null || asset.bytes == null || asset.bytes.Length == 0) { LogSystem.LogError($"[ConfigManager] 加载配置数据失败: {configName}"); return Array.Empty(); } return asset.bytes; } private GameConfig TryReadGameConfig(string path) { if (!File.Exists(path)) return null; try { string json = File.ReadAllText(path); if (string.IsNullOrEmpty(json)) { LogSystem.LogError($"[ConfigManager] 文件为空: {path}"); return null; } var config = JsonUtility.FromJson(json); if (config == null) { LogSystem.LogError($"[ConfigManager] 反序列化结果无效: {path}"); return null; } return config; } catch (Exception e) { LogSystem.LogError($"[ConfigManager] 读取文件失败: {path} | 错误: {e.Message}"); return null; } } private float _lastSaveTime; private const float SaveInterval = 1f; // 最少间隔1秒写一次 public void Update() { if (Config == null || !Config.IsChanged) return; if (Time.time - _lastSaveTime < SaveInterval) return; try { string json = JsonUtility.ToJson(Config); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json); string path = Application.persistentDataPath + "/../Config/game_cfg.json"; FileTools.SafeWriteFile(path, bytes); Config.MarkSaved(); _lastSaveTime = Time.time; } catch (Exception e) { LogSystem.LogError($"[ConfigManager] 保存配置失败: {e.Message}"); } } } [Serializable] public class ModLanguageConfig { public MultilingualType Language; /// /// 按优先级排序的 Mod 文件夹路径列表 /// 索引 0 = 最低优先级(最先应用),最后一项 = 最高优先级(最后应用,可覆盖前面的) /// public List ModPaths = new List(); public ModLanguageConfig() { } public ModLanguageConfig(MultilingualType language) { Language = language; } } [Serializable] public class GameConfig { [SerializeField] private MultilingualType _multilingualType; [SerializeField] private float _musicVolume; [SerializeField] private float _audioVolume; [SerializeField] private bool _showReminder; [SerializeField] private bool _keyMomentEnabled; [SerializeField] private bool _bgmContinuousPlay; [SerializeField] private MultilingualType _secondaryLanguage = MultilingualType.EN; [SerializeField] private List _modLanguageConfigs = new List(); // 老存档迁移标记:第一次进入新版本时,把当前所有本地+订阅 mod 按 targetLanguage 自动挂载到 ModLanguageConfigs;之后此标志置 true 不再触发 // 老存档反序列化时此字段不存在 → 默认 false → 自动触发一次迁移 [SerializeField] private bool _modConfigMigrated; private bool _isChanged; public bool IsChanged => _isChanged; public void MarkSaved() { _isChanged = false; } public MultilingualType MultilingualType { get => _multilingualType; set { if (_multilingualType == value) return; _isChanged = true; _multilingualType = value; } } public float MusicVolume { get => _musicVolume; set { _isChanged = true; _musicVolume = value; } } public float AudioVolume { get => _audioVolume; set { _isChanged = true; _audioVolume = value; } } public bool BgmContinuousPlay { get => _bgmContinuousPlay; set { if (_bgmContinuousPlay == value) return; _isChanged = true; _bgmContinuousPlay = value; } } public bool ShowReminder { get => _showReminder; set { if (_showReminder == value) return; _isChanged = true; _showReminder = value; } } public bool KeyMomentEnabled { get => _keyMomentEnabled; set { if (_keyMomentEnabled == value) return; _isChanged = true; _keyMomentEnabled = value; } } // 默认第二语言:玩家在 Setting 里选择 moreLanguage 选项时切换到此语言。 // 老存档反序列化得到 None 时由 GameConfig() 的初值或加载后兜底刷新成 EN。 public MultilingualType SecondaryLanguage { get => _secondaryLanguage; set { if (_secondaryLanguage == value) return; _isChanged = true; _secondaryLanguage = value; } } /// /// Mod 配置是否已从"全自动 apply"模式迁移到"按 ModLanguageConfigs apply"模式 /// 老存档反序列化默认 false → MultilingualManager.Init 检测到 false 时执行一次性迁移 /// public bool ModConfigMigrated { get => _modConfigMigrated; set { if (_modConfigMigrated == value) return; _isChanged = true; _modConfigMigrated = value; } } public GameConfig() { _multilingualType = MultilingualType.None; _musicVolume = 0.5f; _audioVolume = 0.5f; _showReminder = true; _keyMomentEnabled = true; _bgmContinuousPlay = false; _secondaryLanguage = MultilingualType.EN; _modLanguageConfigs = new List(); // 全新存档不需要迁移(迁移仅针对老版本"全自动 apply"过的玩家) _modConfigMigrated = true; } // ── Mod 优先级配置接口 ── /// 获取所有语种的 Mod 配置列表(只读) public List ModLanguageConfigs => _modLanguageConfigs; /// 获取指定语种的 Mod 配置,不存在则创建 public ModLanguageConfig GetOrCreateModConfig(MultilingualType language) { var config = _modLanguageConfigs.Find(c => c.Language == language); if (config != null) return config; config = new ModLanguageConfig(language); _modLanguageConfigs.Add(config); _isChanged = true; return config; } /// 设置指定语种的 Mod 优先级列表(覆盖现有) public void SetModsForLanguage(MultilingualType language, List orderedPaths) { var config = GetOrCreateModConfig(language); config.ModPaths = new List(orderedPaths); _isChanged = true; } /// 向指定语种添加一个 Mod(加到列表末尾,最高优先级) public void AddModToLanguage(MultilingualType language, string modPath) { var config = GetOrCreateModConfig(language); if (!config.ModPaths.Contains(modPath)) { config.ModPaths.Add(modPath); _isChanged = true; } } /// 从指定语种移除一个 Mod public void RemoveModFromLanguage(MultilingualType language, string modPath) { var config = _modLanguageConfigs.Find(c => c.Language == language); if (config == null) return; if (config.ModPaths.Remove(modPath)) _isChanged = true; } /// 移动指定语种 Mod 的优先级(向上提升=降低索引,向下降低=增加索引) public void MoveModPriority(MultilingualType language, int fromIndex, int toIndex) { var config = _modLanguageConfigs.Find(c => c.Language == language); if (config == null) return; var paths = config.ModPaths; if (fromIndex < 0 || fromIndex >= paths.Count) return; if (toIndex < 0 || toIndex >= paths.Count) return; var item = paths[fromIndex]; paths.RemoveAt(fromIndex); paths.Insert(toIndex, item); _isChanged = true; } /// 清除指定语种的所有 Mod 配置 public void ClearModsForLanguage(MultilingualType language) { var config = _modLanguageConfigs.Find(c => c.Language == language); if (config == null) return; if (config.ModPaths.Count > 0) { config.ModPaths.Clear(); _isChanged = true; } } } }