using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Xml.Linq; using Configs; using UnityEngine; namespace Data { public class PackAbout { public string name; public string description; public string author; public string version; public string packID; public string[] necessary; public string[] after; public string[] before; /// /// 使用静态方法从 XML 文档创建 PackAbout 实例。 /// /// XML 文档。 /// 初始化的 PackAbout 实例。 public static PackAbout FromXDocument(XDocument doc) { var aboutElement = doc.Element("About"); if (aboutElement == null) throw new ArgumentException("XML 文档无效,根节点为空或不是 'About'。"); PackAbout result = new(); result.name = aboutElement.Element("name")?.Value ?? "Unknown"; result.description = aboutElement.Element("description")?.Value ?? "Unknown"; result.author = aboutElement.Element("author")?.Value ?? "Unknown"; result.version = aboutElement.Element("version")?.Value ?? "Unknown"; result.packID = aboutElement.Element("packID")?.Value ?? "Unknown"; var sortElement = aboutElement.Element("sort"); if (sortElement != null) { result.before = GetElementValues(sortElement.Element("before")); result.after = GetElementValues(sortElement.Element("after")); result.necessary = GetElementValues(sortElement.Element("necessary")); } else { result.before = Array.Empty(); result.after = Array.Empty(); result.necessary = Array.Empty(); } return result; } /// /// 获取指定 XElement 下所有子元素的值并返回为字符串数组。 /// /// 父 XElement。 /// 字符串数组。 private static string[] GetElementValues(XElement element) { if (element == null || !element.HasElements) return Array.Empty(); return element.Elements() .Select(e => e.Value.Trim()) .ToArray(); } public override string ToString() { // 定义字段标签和值的对齐格式(如左对齐,固定宽度) const int labelWidth = -12; // 负数为左对齐 const int valueWidth = -30; // 负数为左对齐 // 使用StringBuilder高效拼接 var sb = new StringBuilder(); // 基础字段(单行) sb.AppendLine($"{"Name:",labelWidth}{name,valueWidth}"); sb.AppendLine($"{"Description:",labelWidth}{description,valueWidth}"); sb.AppendLine($"{"Author:",labelWidth}{author,valueWidth}"); sb.AppendLine($"{"Version:",labelWidth}{version,valueWidth}"); sb.AppendLine($"{"PackID:",labelWidth}{packID,valueWidth}"); // 数组字段(多行,每项缩进) sb.AppendLine( $"{"Necessary:",labelWidth}{string.Join(", ", necessary ?? Array.Empty()),valueWidth}"); sb.AppendLine($"{"After:",labelWidth}{string.Join(", ", after ?? Array.Empty()),valueWidth}"); sb.AppendLine($"{"Before:",labelWidth}{string.Join(", ", before ?? Array.Empty()),valueWidth}"); return sb.ToString(); } } public class DefinePack { private const string CoreNamespace = "Data."; /// /// define类别及其定义 /// public Dictionary> defines; public PackAbout packAbout; public string packID; public bool LoadPack(string packPath) { var packDatas = ConfigProcessor.LoadXmlFromPath(packPath); var aboutXmls = FindDocumentsWithRootName(packDatas, "About"); if (aboutXmls == null || aboutXmls.Count < 1) { Debug.LogError("包缺少配置文件,加载跳过"); return false; } var aboutXml = aboutXmls[0]; packAbout = PackAbout.FromXDocument(aboutXml); packID = packAbout.packID; if (aboutXmls.Count > 1) Debug.LogWarning($"{packAbout.name}包拥有多个配置文件,系统选择了加载序的第一个,请避免这种情况"); var defineXmls = FindDocumentsWithRootName(aboutXmls, "Define"); foreach (var defineXml in defineXmls) LoadDefines(defineXml); return true; } private void LoadDefines(XDocument defineDoc) { var rootElement = defineDoc.Root; if (rootElement == null || rootElement.Name != "Define") return; foreach (var element in rootElement.Elements()) { var className = element.Name.ToString(); if (string.IsNullOrEmpty(className)) continue; var def = LoadDefineClass(element); if (def == null) continue; if (!defines.ContainsKey(className)) defines.Add(className, new List()); defines[className].Add(def); } } private Define LoadDefineClass(XElement defineDoc) { var className = defineDoc.Name.ToString(); var assembly = Assembly.GetExecutingAssembly(); Type type; if (!className.Contains('.')) { // 尝试拼接默认命名空间 var fullClassName = CoreNamespace + className; type = assembly.GetType(fullClassName); // 如果拼接命名空间后仍找不到,尝试直接查找(可能是全局命名空间下的类) if (type == null) type = assembly.GetType(className); } else { // 直接查找 type = assembly.GetType(className); } if (type == null) { Debug.LogError($"未定义的类型: {className}"); return null; } var constructor = type.GetConstructor(Type.EmptyTypes); if (constructor == null) { Debug.LogError($"{className} 必须包含无参构造函数"); return null; } // 3. 创建实例 object instance; try { instance = Activator.CreateInstance(type); } catch (Exception ex) { Debug.LogError($"创建 {className} 实例失败: {ex.Message}"); return null; } // 4. 检查是否继承自 Define if (instance is not Define define) { Debug.LogError($"{className} 必须继承自 Define"); return null; } if (define.Init(defineDoc)) return define; // 获取类的所有字段(不包括私有字段) var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); // 遍历字段并尝试从 XElement 中赋值 foreach (var field in fields) { // 查找对应的 XElement 子元素 var element = defineDoc.Element(field.Name); if (element != null) try { // 将子元素的值转换为目标类型并赋值 var value = Convert.ChangeType(element.Value, field.FieldType); field.SetValue(define, value); } catch (Exception ex) { Debug.LogWarning($"Error setting field {field.Name}: {ex.Message}"); } } return define; } /// /// 从 ListXDocument 中查找指定根元素名称的文档。 /// /// XML 文档列表。 /// 目标根元素名称。 /// 符合条件的 XML 文档列表。 public static List FindDocumentsWithRootName(List xmlDocuments, string rootName) { // Using LINQ to Objects for a more concise solution var result = xmlDocuments .Where(doc => doc.Root != null && doc.Root.Name.LocalName == rootName) .ToList(); return result; } public override string ToString() { // 对齐格式(左对齐,固定宽度) const int labelWidth = -15; const int valueWidth = -30; var sb = new StringBuilder(); // 基础字段 sb.AppendLine($"{"PackID:",labelWidth}{packID,valueWidth}"); sb.AppendLine(); // PackAbout 对象 sb.AppendLine("=== PackAbout ==="); sb.AppendLine(packAbout?.ToString() ?? "N/A"); // 调用 PackAbout 的 ToString() sb.AppendLine(); // 字典字段(defines) sb.AppendLine("=== Defines ==="); if (defines != null && defines.Count > 0) foreach (var kvp in defines) { sb.AppendLine($"【{kvp.Key}】"); // 输出字典的键(类别名) foreach (var define in kvp.Value) // 遍历该类别下的所有 Define 对象 sb.AppendLine(define.ToString()); // 调用 Define 的 ToString() sb.AppendLine(); // 每个类别后空一行 } else sb.AppendLine("No defines found."); return sb.ToString(); } } }