Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Configs/ConfigManager.cs

230 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using System.IO;
using Managers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
namespace Configs
{
/// <summary>
/// 配置管理器,采用单例模式,负责读取、修改、存储应用程序配置。
/// 继承自 Utils.Singleton<ConfigManager> 和 ILaunchManager。
/// </summary>
public class ConfigManager : Utils.Singleton<ConfigManager>, ILaunchManager
{
/// <summary>
/// 配置文件名
/// </summary>
private const string CONFIG_FILE_NAME = "app_config.json";
/// <summary>
/// 完整的配置文件路径
/// Application.persistentDataPath 在PC上是 C:/Users/用户名/AppData/LocalLow/公司名/项目名/
/// 在Android/iOS上是持久存储路径。
/// </summary>
private readonly string _configFilePath;
/// <summary>
/// 存储配置数据的字典。使用 JToken 允许存储任意 JSON 类型(基本类型、对象、数组)。
/// </summary>
private Dictionary<string, JToken> _configData;
/// <summary>
/// 私有构造函数,由 Singleton 基类调用。
/// </summary>
public ConfigManager()
{
_configFilePath = Path.Combine(Application.persistentDataPath, CONFIG_FILE_NAME);
_configData = new Dictionary<string, JToken>();
Debug.Log($"ConfigManager initialized. Config file path: {_configFilePath}");
}
public string StepDescription => "载入配置文件";
/// <summary>
/// 初始化配置管理器,加载配置文件。
/// 如果配置文件不存在,将创建一个默认配置。
/// </summary>
public void Init()
{
LoadConfig();
}
/// <summary>
/// 清理配置管理器,释放内存中的配置数据。
/// 注意:此方法不会自动保存配置。如果需要在清理前保存,请手动调用 Save()。
/// </summary>
public void Clear()
{
_configData.Clear();
}
/// <summary>
/// 从配置文件加载配置数据到内存。
/// 如果文件不存在,则创建默认配置并保存。
/// </summary>
private void LoadConfig()
{
if (File.Exists(_configFilePath))
{
try
{
string json = File.ReadAllText(_configFilePath);
_configData = JsonConvert.DeserializeObject<Dictionary<string, JToken>>(json);
}
catch (JsonException ex)
{
Debug.LogError(
$"ConfigManager: Failed to deserialize config file. Creating default config. Error: {ex.Message}");
CreateDefaultConfig();
SaveConfig(); // 保存默认配置
}
catch (IOException ex)
{
Debug.LogError(
$"ConfigManager: Failed to read config file. Creating default config. Error: {ex.Message}");
CreateDefaultConfig();
SaveConfig(); // 保存默认配置
}
}
else
{
Debug.Log("ConfigManager: Config file not found. Creating default config.");
CreateDefaultConfig();
SaveConfig(); // 保存默认配置
}
}
/// <summary>
/// 创建一个默认的空配置或包含初始值的配置。
/// </summary>
private void CreateDefaultConfig()
{
_configData = new Dictionary<string, JToken>();
SetValue("playerAffiliation","player");
SetValue("outsideDimension","DefaultOutsideDimension");
SetValue("insideDimension","DefaultInsideDimension");
}
/// <summary>
/// 将内存中的配置数据保存到配置文件。
/// </summary>
public void SaveConfig()
{
try
{
// 使用 Formatting.Indented 使 JSON 文件更具可读性
string json = JsonConvert.SerializeObject(_configData, Formatting.Indented);
File.WriteAllText(_configFilePath, json);
Debug.Log("ConfigManager: Configuration saved successfully.");
}
catch (JsonException ex)
{
Debug.LogError($"ConfigManager: Failed to serialize config data. Error: {ex.Message}");
}
catch (IOException ex)
{
Debug.LogError($"ConfigManager: Failed to write config file. Error: {ex.Message}");
}
}
/// <summary>
/// 获取指定键的配置值。
/// </summary>
/// <typeparam name="T">值的目标类型。</typeparam>
/// <param name="key">配置项的键。</param>
/// <param name="defaultValue">如果键不存在或类型转换失败,返回的默认值。</param>
/// <returns>配置值或默认值。</returns>
public T GetValue<T>(string key, T defaultValue = default(T))
{
if (_configData.TryGetValue(key, out JToken jToken))
{
try
{
// JToken.ToObject<T>() 能够智能地将 JToken 转换为目标类型 T
return jToken.ToObject<T>();
}
catch (JsonException ex)
{
Debug.LogWarning(
$"ConfigManager: Failed to convert value for key '{key}' to type '{typeof(T).Name}'. " +
$"Returning default value. Error: {ex.Message}");
return defaultValue;
}
}
Debug.LogWarning($"ConfigManager: Key '{key}' not found. Returning default value '{defaultValue}'.");
return defaultValue;
}
/// <summary>
/// 设置指定键的配置值。
/// </summary>
/// <typeparam name="T">值的类型。</typeparam>
/// <param name="key">配置项的键。</param>
/// <param name="value">要设置的值。</param>
public void SetValue<T>(string key, T value)
{
if (string.IsNullOrEmpty(key))
{
Debug.LogError("ConfigManager: Cannot set value with an empty or null key.");
return;
}
try
{
// JToken.FromObject(value) 能够将任何对象转换为 JToken
_configData[key] = JToken.FromObject(value);
Debug.Log(
$"ConfigManager: Value for key '{key}' set to '{value}'. Remember to call SaveConfig() to persist changes.");
}
catch (JsonException ex)
{
Debug.LogError(
$"ConfigManager: Failed to convert value '{value}' for key '{key}' to JToken. Error: {ex.Message}");
}
}
/// <summary>
/// 检查配置中是否存在某个键。
/// </summary>
/// <param name="key">要检查的键。</param>
/// <returns>如果存在该键,则为 true否则为 false。</returns>
public bool ContainsKey(string key)
{
return _configData.ContainsKey(key);
}
/// <summary>
/// 移除指定键的配置项。
/// </summary>
/// <param name="key">要移除的键。</param>
/// <returns>如果成功移除,则为 true否则为 false。</returns>
public bool RemoveKey(string key)
{
if (_configData.Remove(key))
{
Debug.Log($"ConfigManager: Key '{key}' removed. Remember to call SaveConfig() to persist changes.");
return true;
}
Debug.LogWarning($"ConfigManager: Attempted to remove non-existent key '{key}'.");
return false;
}
/// <summary>
/// 直接获取原始的 JToken 值,适用于处理复杂或嵌套的 JSON 结构。
/// </summary>
/// <param name="key">配置项的键。</param>
/// <returns>对应的 JToken如果键不存在则为 null。</returns>
public JToken GetRawJToken(string key)
{
_configData.TryGetValue(key, out JToken jToken);
return jToken;
}
}
}