using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Xml.Linq; using Configs; using UnityEngine; using Object = System.Object; 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=new(); 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(packDatas, "Define"); // Debug.Log($"Define文件数量{defineXmls.Count}"); 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,element.Name.ToString()); if (def == null) continue; def.packID = packID; if (!defines.ContainsKey(className)) defines.Add(className, new List()); defines[className].Add(def); } } /// /// 根据指定的 XML 元素 () 和类名 (), /// 动态加载并初始化一个继承自 的类实例。 /// /// 包含类定义的 XML 元素 ()。 /// 目标类的全限定名或简短名称。 /// /// 如果成功加载并初始化,则返回对应的 类实例; /// 否则返回 null。 /// /// /// 如果 为 null 或空字符串,则抛出此异常。 /// /// /// 该方法通过反射动态加载指定类,并检查其是否继承自 。 /// 如果类存在且满足条件,则尝试调用其 方法进行初始化。 /// 如果初始化失败,则使用默认初始化方法 ()。 /// public static Define LoadDefineClass(XElement defineDoc,string className) { 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; DefaultInitDefine(define,defineDoc, type); return define; } /// /// 初始化指定的 对象,根据 中的 XML 元素内容, /// 将对应的字段值赋给 对象。 /// /// 需要初始化的对象实例。 /// 包含字段定义的 XML 元素 ()。 /// 目标对象的类型 ()。 /// /// 如果 为 null,则抛出此异常。 /// /// /// 该方法会遍历 的所有字段(包括公共和非公共字段), /// 并尝试从 中找到与字段名称匹配的子元素。 /// 如果找到匹配的子元素,则将其值转换为字段的类型并赋值给字段。 /// 如果字段类型继承自 ,则递归调用 方法进行加载。 /// public static void DefaultInitDefine(Define define,XElement defineDoc,Type defineType) { var fields = defineType.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); // 遍历字段并尝试从 XElement 中赋值 foreach (var field in fields) { // 查找对应的 XElement 子元素 var element = defineDoc.Element(field.Name); if (element != null) try { Object value; if (IsFieldTypeInheritedFrom(field, typeof(Define))) { if (element.HasElements) { value = LoadDefineClass(element, field.FieldType.Name); } else { value = new DefineReference(field.FieldType.Name, element.Value, field.Name); } } else value = Convert.ChangeType(element.Value, field.FieldType); field.SetValue(define, value); } catch (Exception ex) { Debug.LogWarning($"Error setting field {field.Name}: {ex.Message}"); } } } /// /// 从 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(); } /// /// 检查字段的类型是否继承自指定的类 /// /// 字段信息 /// 要检查的基类类型 /// 如果字段的类型是基类或其派生类,则返回 true public static bool IsFieldTypeInheritedFrom(FieldInfo field, Type baseType) { // 获取字段的类型 var fieldType = field.FieldType; // 如果字段的类型为 null 或不是基类的派生类,则返回 false if (!baseType.IsAssignableFrom(fieldType)) return false; // 如果字段的类型直接是基类或其派生类,则返回 true return fieldType != baseType && baseType.IsAssignableFrom(fieldType); } } }