using System.Text.Json; using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Api.Utility { /// /// 简易的插件配置文件生成器 /// 仅支持部分基本类型(, , , , )及其数组(List<long>, List<double>, List<decimal>, List<string>, List<bool>long[], double[], decimal[], string[], bool[]) /// 文件会保存为:程序目录/(通常是 configs)//.json /// /// /// 新建一个配置文件,文件会保存为:程序目录/(通常是 configs)//.json /// /// /// public class PluginConfig(string plugin_name, string file_name) : Dictionary { /// /// 配置文件存放的根目录 /// public static string RootPath { get; set; } = "configs"; /// /// 插件的名称 /// public string PluginName { get; set; } = plugin_name; /// /// 配置文件的名称(后缀将是.json) /// public string FileName { get; set; } = file_name; /// /// 使用索引器给指定key赋值,不存在key会新增 /// /// /// public new object this[string key] { get => base[key]; set { if (value != null) Add(key, value); } } /// /// 如果保存了对象,请使用此方法转换 /// /// /// public void Parse(string key) { if (TryGetValue(key, out object? value) && value != null) { T? instance = NetworkUtility.JsonDeserialize(value.ToString() ?? ""); if (instance != null) { base[key] = instance; } } } /// /// 获取指定key的value /// /// /// public object? GetValue(string key) { if (base.TryGetValue(key, out object? value) && value != null) { return value; } return null; } /// /// 使用泛型获取指定key的value /// /// /// /// public T? Get(string key) { if (TryGetValue(key, out object? value) && value != null) { if (value is T typeValue) { return typeValue; } if (value is List listValue) { return NetworkUtility.JsonDeserialize(NetworkUtility.JsonSerialize(listValue)); } if (value is Dictionary dictValue) { return NetworkUtility.JsonDeserialize(NetworkUtility.JsonSerialize(dictValue)); } return NetworkUtility.JsonDeserialize(value.ToString() ?? ""); } return default; } /// /// 添加一个配置,如果已存在key会覆盖 /// /// /// public new void Add(string key, object value) { if (value != null) { if (TryGetValue(key, out _)) base[key] = value; else base.Add(key, value); } } /// /// 从配置文件中读取配置。 /// 注意:所有保存时为数组的对象都会变成对象,并且不支持类型 /// public void LoadConfig() { string dpath = $@"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, RootPath)}/{PluginName}"; string fpath = $@"{dpath}/{FileName}.json"; if (!Directory.Exists(dpath)) { Directory.CreateDirectory(dpath); } if (File.Exists(fpath)) { string json = File.ReadAllText(fpath, General.DefaultEncoding); Dictionary dict = NetworkUtility.JsonDeserialize>(json) ?? []; Clear(); foreach (string key in dict.Keys) { JsonElement obj = (JsonElement)dict[key]; AddValue(key, obj); } } } /// /// 将配置保存到配置文件。调用此方法会覆盖原有的.json,请注意备份 /// public void SaveConfig() { string json = NetworkUtility.JsonSerialize((Dictionary)this); string dpath = $@"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, RootPath)}/{PluginName}"; string fpath = $@"{dpath}/{FileName}.json"; if (!Directory.Exists(dpath)) { Directory.CreateDirectory(dpath); } using StreamWriter writer = new(fpath, false, General.DefaultEncoding); writer.WriteLine(json); writer.Flush(); } /// /// Json反序列化的方法 /// /// /// private void AddValue(string key, JsonElement obj) { switch (obj.ValueKind) { case JsonValueKind.Object: base.Add(key, obj); break; case JsonValueKind.Number: if (obj.ValueKind == JsonValueKind.Number && obj.TryGetInt64(out long longValue)) { base.Add(key, longValue); } else if (obj.ValueKind == JsonValueKind.Number && obj.TryGetDouble(out double douValue)) { base.Add(key, douValue); } else if (obj.ValueKind == JsonValueKind.Number && obj.TryGetDecimal(out decimal decValue)) { base.Add(key, decValue); } break; case JsonValueKind.String: base.Add(key, obj.GetString() ?? ""); break; case JsonValueKind.True: case JsonValueKind.False: base.Add(key, obj.GetBoolean()); break; case JsonValueKind.Array: AddValues(key, obj.EnumerateArray()); break; } } /// /// JSON 数组反序列化的方法,支持特定类型数组和混合类型数组(包括嵌套对象和数组)。 /// /// 字典的键 /// JSON 数组的枚举器 private void AddValues(string key, JsonElement.ArrayEnumerator obj) { List longList = []; List douList = []; List decList = []; List strList = []; List bolList = []; List resultList = []; // 标记是否为混合类型 bool isMixed = false; // 记录第一个非 null 元素的类型 JsonValueKind? firstValueKind = null; foreach (JsonElement arrayElement in obj) { switch (arrayElement.ValueKind) { case JsonValueKind.Number when arrayElement.TryGetInt64(out long longValue): longList.Add(longValue); resultList.Add(longValue); firstValueKind ??= JsonValueKind.Number; if (firstValueKind != JsonValueKind.Number) isMixed = true; break; case JsonValueKind.Number when arrayElement.TryGetDouble(out double doubleValue): douList.Add(doubleValue); resultList.Add(doubleValue); firstValueKind ??= JsonValueKind.Number; if (firstValueKind != JsonValueKind.Number) isMixed = true; break; case JsonValueKind.Number when arrayElement.TryGetDecimal(out decimal decimalValue): decList.Add(decimalValue); resultList.Add(decimalValue); firstValueKind ??= JsonValueKind.Number; if (firstValueKind != JsonValueKind.Number) isMixed = true; break; case JsonValueKind.String: string strValue = arrayElement.GetString() ?? ""; strList.Add(strValue); resultList.Add(strValue); firstValueKind ??= JsonValueKind.String; if (firstValueKind != JsonValueKind.String) isMixed = true; break; case JsonValueKind.True: case JsonValueKind.False: bool boolValue = arrayElement.GetBoolean(); bolList.Add(boolValue); resultList.Add(boolValue); firstValueKind ??= arrayElement.ValueKind; if (firstValueKind != arrayElement.ValueKind) isMixed = true; break; case JsonValueKind.Null: break; case JsonValueKind.Object: Dictionary objValue = ParseObject(arrayElement); resultList.Add(objValue); isMixed = true; break; case JsonValueKind.Array: List arrayValue = ParseArray(arrayElement); resultList.Add(arrayValue); isMixed = true; break; default: isMixed = true; break; } } // 根据类型一致性选择存储的列表 if (resultList.Count > 0) { if (!isMixed) { // 所有元素类型一致,存储到对应的特定类型列表 switch (firstValueKind) { case JsonValueKind.Number when longList.Count == resultList.Count: base.Add(key, longList); break; case JsonValueKind.Number when douList.Count == resultList.Count: base.Add(key, douList); break; case JsonValueKind.Number when decList.Count == resultList.Count: base.Add(key, decList); break; case JsonValueKind.String: base.Add(key, strList); break; case JsonValueKind.True: case JsonValueKind.False: base.Add(key, bolList); break; default: base.Add(key, resultList); // 包含 null 或未知情况 break; } } else { // 混合类型或包含对象/数组,存储为 List base.Add(key, resultList); } } } /// /// 递归解析 JSON 对象 /// private Dictionary ParseObject(JsonElement element) { Dictionary dict = []; foreach (JsonProperty property in element.EnumerateObject()) { object? value = property.Value.ValueKind switch { JsonValueKind.Number when property.Value.TryGetInt64(out long longValue) => longValue, JsonValueKind.Number when property.Value.TryGetDouble(out double doubleValue) => doubleValue, JsonValueKind.Number when property.Value.TryGetDecimal(out decimal decimalValue) => decimalValue, JsonValueKind.String => property.Value.GetString() ?? "", JsonValueKind.True => true, JsonValueKind.False => false, JsonValueKind.Null => null, JsonValueKind.Object => ParseObject(property.Value), JsonValueKind.Array => ParseArray(property.Value), _ => null }; if (value != null) dict.Add(property.Name, value); } return dict; } /// /// 递归解析 JSON 数组 /// private List ParseArray(JsonElement element) { List list = []; foreach (JsonElement arrayElement in element.EnumerateArray()) { object? value = arrayElement.ValueKind switch { JsonValueKind.Number when arrayElement.TryGetInt64(out long longValue) => longValue, JsonValueKind.Number when arrayElement.TryGetDouble(out double doubleValue) => doubleValue, JsonValueKind.Number when arrayElement.TryGetDecimal(out decimal decimalValue) => decimalValue, JsonValueKind.String => arrayElement.GetString() ?? "", JsonValueKind.True => true, JsonValueKind.False => false, JsonValueKind.Null => null, JsonValueKind.Object => ParseObject(arrayElement), JsonValueKind.Array => ParseArray(arrayElement), _ => null }; if (value != null) list.Add(value); } return list; } } }