using System.Collections.Generic; using System.IO; using Managers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; namespace Configs { /// /// 配置管理器,采用单例模式,负责读取、修改、存储应用程序配置。 /// 继承自 Utils.Singleton<ConfigManager> 和 ILaunchManager。 /// public class ConfigManager : Utils.Singleton, ILaunchManager { /// /// 配置文件名 /// private const string CONFIG_FILE_NAME = "app_config.json"; /// /// 完整的配置文件路径,文件位于程序的可执行文件同级目录。 /// 在编辑器中:通常是 Assets 文件夹的父目录。 /// 在构建后:与可执行文件(例如 .exe)在同一目录下。 /// private readonly string _configFilePath; /// /// 存储配置数据的字典。使用 JToken 允许存储任意 JSON 类型(基本类型、对象、数组)。 /// private Dictionary _configData; /// /// 私有构造函数,由 Singleton 基类调用。 /// public ConfigManager() { string appDirectory = Path.GetDirectoryName(Application.dataPath); if (string.IsNullOrEmpty(appDirectory)) { appDirectory = Application.dataPath; } _configFilePath = Path.Combine(appDirectory, CONFIG_FILE_NAME); _configData = new Dictionary(); Debug.Log($"ConfigManager 初始化。配置文件路径: {_configFilePath}"); } public string StepDescription => "载入配置文件"; /// /// 初始化配置管理器,加载配置文件。 /// 如果配置文件不存在,将创建一个默认配置。 /// public void Init() { LoadConfig(); } /// /// 清理配置管理器,释放内存中的配置数据。 /// 注意:此方法不会自动保存配置。如果需要在清理前保存,请手动调用 Save()。 /// public void Clear() { _configData.Clear(); } /// /// 从配置文件加载配置数据到内存。 /// 如果文件不存在,则创建默认配置并保存。 /// private void LoadConfig() { if (File.Exists(_configFilePath)) { try { var json = File.ReadAllText(_configFilePath); if (string.IsNullOrWhiteSpace(json)) { Debug.LogWarning($"ConfigManager: 配置文件 '{_configFilePath}' 为空。正在创建默认配置。"); CreateDefaultConfig(); SaveConfig(); return; } _configData = JsonConvert.DeserializeObject>(json); if (_configData == null) { Debug.LogWarning($"ConfigManager: 配置文件 '{_configFilePath}' 包含无效结构。正在创建默认配置。"); CreateDefaultConfig(); SaveConfig(); } } catch (JsonException ex) { Debug.LogError( $"ConfigManager: 反序列化配置文件 '{_configFilePath}' 失败。正在创建默认配置。错误: {ex.Message}"); CreateDefaultConfig(); SaveConfig(); } catch (IOException ex) { Debug.LogError( $"ConfigManager: 读取配置文件 '{_configFilePath}' 失败。正在创建默认配置。错误: {ex.Message}"); CreateDefaultConfig(); SaveConfig(); } } else { Debug.Log($"ConfigManager: 配置文件 '{_configFilePath}' 未找到。正在创建默认配置。"); CreateDefaultConfig(); SaveConfig(); } } /// /// 创建一个默认的空配置或包含初始值的配置。 /// private void CreateDefaultConfig() { _configData = new Dictionary(); SetValue("playerAffiliation", "player"); SetValue("outsideDimension", "DefaultOutsideDimension"); SetValue("insideDimension", "DefaultInsideDimension"); SetValue("baseDimension", "DefaultBaseDimension"); SetValue("configVersion", 1); } /// /// 将内存中的配置数据保存到配置文件。 /// public void SaveConfig() { try { var json = JsonConvert.SerializeObject(_configData, Formatting.Indented); File.WriteAllText(_configFilePath, json); Debug.Log($"ConfigManager: 配置已保存到 '{_configFilePath}'。"); } catch (JsonException ex) { Debug.LogError($"ConfigManager: 序列化配置数据失败。错误: {ex.Message}"); } catch (IOException ex) { Debug.LogError($"ConfigManager: 写入配置文件 '{_configFilePath}' 失败。请检查权限。错误: {ex.Message}"); } catch (System.UnauthorizedAccessException ex) { Debug.LogError($"ConfigManager: 写入配置文件 '{_configFilePath}' 权限被拒绝。请以管理员身份运行或更改文件夹权限。错误: {ex.Message}"); } } /// /// 获取指定键的配置值。 /// /// 值的目标类型。 /// 配置项的键。 /// 如果键不存在或类型转换失败,返回的默认值。 /// 配置值或默认值。 public T GetValue(string key, T defaultValue = default(T)) { if (_configData.TryGetValue(key, out var jToken)) { try { return jToken.ToObject(); } catch (JsonException ex) { Debug.LogWarning( $"ConfigManager: 键 '{key}' 的值从 '{jToken}' 转换为类型 '{typeof(T).Name}' 失败。" + $"返回默认值 '{defaultValue}'。错误: {ex.Message}"); return defaultValue; } catch (System.FormatException ex) { Debug.LogWarning( $"ConfigManager: 键 '{key}' 的值从 '{jToken}' 转换为类型 '{typeof(T).Name}' 时格式错误。" + $"返回默认值 '{defaultValue}'。错误: {ex.Message}"); return defaultValue; } } Debug.LogWarning($"ConfigManager: 未找到键 '{key}'。返回默认值 '{defaultValue}'。"); return defaultValue; } /// /// 设置指定键的配置值。 /// /// 值的类型。 /// 配置项的键。 /// 要设置的值。 public void SetValue(string key, T value) { if (string.IsNullOrEmpty(key)) { Debug.LogError("ConfigManager: 键不能为空。"); return; } try { _configData[key] = JToken.FromObject(value); Debug.Log( $"ConfigManager: 键 '{key}' 的值设置为 '{value}'。请调用 SaveConfig() 持久化更改。"); } catch (JsonException ex) { Debug.LogError( $"ConfigManager: 键 '{key}' 的值 '{value}' 转换为 JToken 失败。错误: {ex.Message}"); } } /// /// 检查配置中是否存在某个键。 /// /// 要检查的键。 /// 如果存在该键,则为 true;否则为 false。 public bool ContainsKey(string key) { return _configData.ContainsKey(key); } /// /// 移除指定键的配置项。 /// /// 要移除的键。 /// 如果成功移除,则为 true;否则为 false。 public bool RemoveKey(string key) { if (_configData.Remove(key)) { Debug.Log($"ConfigManager: 键 '{key}' 已移除。请调用 SaveConfig() 持久化更改。"); return true; } Debug.LogWarning($"ConfigManager: 尝试移除不存在的键 '{key}'。"); return false; } /// /// 直接获取原始的 JToken 值,适用于处理复杂或嵌套的 JSON 结构。 /// /// 配置项的键。 /// 对应的 JToken;如果键不存在,则为 null。 public JToken GetRawJToken(string key) { _configData.TryGetValue(key, out var jToken); return jToken; } } }