using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Xml.Linq; using Configs; using UnityEngine; namespace Data { /// /// 表示模组包的基本信息。 /// public class PackAbout { private const string RootElementName = "About"; private const string ElementName_Name = "name"; private const string ElementName_Description = "description"; private const string ElementName_Author = "author"; private const string ElementName_Version = "version"; private const string ElementName_PackID = "packID"; private const string ElementName_Sort = "sort"; private const string ElementName_Before = "before"; private const string ElementName_After = "after"; private const string ElementName_Necessary = "necessary"; public string Name { get; private set; } public string Description { get; private set; } public string Author { get; private set; } public string Version { get; private set; } public string PackID { get; private set; } public string[] Necessary { get; private set; } public string[] After { get; private set; } public string[] Before { get; private set; } /// /// 使用静态方法从 XML 文档创建 PackAbout 实例。 /// /// XML 文档。 /// 初始化的 PackAbout 实例。 /// 当 XML 文档无效,根节点为空或不是 'About' 时抛出。 public static PackAbout FromXDocument(XDocument doc) { var aboutElement = doc.Element(RootElementName); if (aboutElement == null) throw new ArgumentException($"XML 文档无效,根节点为空或不是 '{RootElementName}'。"); PackAbout result = new(); result.Name = aboutElement.Element(ElementName_Name)?.Value ?? "Unknown"; result.Description = aboutElement.Element(ElementName_Description)?.Value ?? "Unknown"; result.Author = aboutElement.Element(ElementName_Author)?.Value ?? "Unknown"; result.Version = aboutElement.Element(ElementName_Version)?.Value ?? "Unknown"; result.PackID = aboutElement.Element(ElementName_PackID)?.Value ?? "Unknown"; var sortElement = aboutElement.Element(ElementName_Sort); if (sortElement != null) { result.Before = GetElementValues(sortElement.Element(ElementName_Before)); result.After = GetElementValues(sortElement.Element(ElementName_After)); result.Necessary = GetElementValues(sortElement.Element(ElementName_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; // 负数为左对齐 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."; private const string RootElementName_About = "About"; private const string RootElementName_Define = "Define"; // 反射缓存 private static readonly Dictionary _typeCache = new(); private static readonly Dictionary _constructorCache = new(); private static readonly Dictionary _fieldCache = new(); private static readonly List _assembliesToSearch = new(); // 缓存要搜索的程序集 /// /// 定义类别及其定义。 /// public Dictionary> defines = new(); public PackAbout packAbout; public string packID; public string packRootPath; public int priority = -1; static DefinePack() { // 初始化要搜索的程序集。 _assembliesToSearch.AddRange(AppDomain.CurrentDomain.GetAssemblies()); } public string Name => // 使用 PackAbout.Name 属性,若为空则返回默认值。 packAbout?.Name ?? "Unnamed Pack"; /// /// 加载模组包。 /// /// 模组包的路径。 /// 如果模组包加载成功,则为 true;否则为 false。 public bool LoadPack(string packPath) { packRootPath = Path.GetFullPath(packPath); var packDatas = ConfigProcessor.LoadXmlFromPath(packPath); var aboutXmls = FindDocumentsWithRootName(packDatas, RootElementName_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, RootElementName_Define); foreach (var defineXml in defineXmls) LoadDefines(defineXml); return true; } /// /// 加载定义。 /// /// 包含定义的 XML 文档。 private void LoadDefines(XDocument defineDoc) { var rootElement = defineDoc.Root; if (rootElement == null) { Debug.LogWarning("加载定义时发现一个XML文档的根元素为空,跳过此文档。"); return; } if (rootElement.Name != RootElementName_Define) { Debug.LogWarning( $"加载定义时发现XML文档根元素名称 '{rootElement.Name}' 不符合预期 '{RootElementName_Define}',跳过此文档。"); return; } foreach (var element in rootElement.Elements()) { var className = element.Name.ToString(); if (string.IsNullOrEmpty(className)) continue; var def = LoadDefineClass(element, className); if (def == null) continue; def.packID = packID; if (!defines.ContainsKey(className)) defines.Add(className, new List()); defines[className].Add(def); } } /// /// 根据指定的 XML 元素 () 和类名 (), /// 动态加载并初始化一个继承自 的类实例。 /// /// 包含类定义的 XML 元素 ()。 /// 目标类的全限定名或简短名称。 /// /// 如果成功加载并初始化,则返回对应的 类实例; /// 否则返回 null。 /// public static Define LoadDefineClass(XElement defineDoc, string className) { // 反射缓存和改进的类型查找 if (!_typeCache.TryGetValue(className, out var type)) { // 尝试 CoreNamespace + className var fullClassName = CoreNamespace + className; type = _assembliesToSearch.Select(a => a.GetType(fullClassName)).FirstOrDefault(t => t != null); // 如果未找到,尝试不使用 CoreNamespace if (type == null) type = _assembliesToSearch.Select(a => a.GetType(className)).FirstOrDefault(t => t != null); if (type == null) { Debug.LogError($"未定义的类型: {className}。"); return null; } _typeCache[className] = type; } // 构造函数缓存 if (!_constructorCache.TryGetValue(type, out var constructor)) { constructor = type.GetConstructor(Type.EmptyTypes); if (constructor == null) { Debug.LogError($"类 {className} 必须包含无参构造函数。"); return null; } _constructorCache[type] = constructor; } // 创建实例 object instance; try { instance = constructor.Invoke(null); } catch (Exception ex) { Debug.LogError($"创建 {className} 实例失败: {ex.Message}。"); return null; } // 检查是否继承自 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 元素 ()。 /// 目标对象的类型 ()。 public static void DefaultInitDefine(Define define, XElement defineDoc, Type defineType) { // FieldInfo 缓存 if (!_fieldCache.TryGetValue(defineType, out var fields)) { fields = defineType.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); _fieldCache[defineType] = fields; } // 遍历字段并尝试从 XElement 中赋值 foreach (var field in fields) { // 查找对应的 XElement 子元素 var element = defineDoc.Element(field.Name); if (element != null) try { var value = ConvertXElementValueToType(element, field.FieldType); field.SetValue(define, value); } catch (Exception ex) { Debug.LogWarning( $"设置字段时出错,字段名: {field.Name}; 值: {element.Value}; 错误: {ex.Message}。"); } } var properties = defineType .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic) // 也获取私有属性,但要求私有属性有 setter .Where(p => p.CanWrite); // 只要可写就可以设置 foreach (var property in properties) { var element = defineDoc.Element(property.Name); if (element != null) try { var value = ConvertXElementValueToType(element, property.PropertyType); property.SetValue(define, value); } catch (Exception ex) { Debug.LogWarning( $"设置属性 '{property.Name}' 时出错,值: '{element.Value}',错误: {ex.Message}。"); } } } /// /// 将 XElement 值转换为特定类型。 /// /// XElement 元素。 /// 目标类型。 /// 转换后的值。 private static object ConvertXElementValueToType(XElement element, Type targetType) { if (IsTypeInheritedFrom(targetType, typeof(Define))) { if (element.HasElements) return LoadDefineClass(element, targetType.Name); // 引用另一个 Define var reference = (Define)Activator.CreateInstance(targetType); reference.isReferene = true; reference.description = targetType.Name; reference.label = element.Name.LocalName; // 使用元素的名称作为标签 reference.defName = element.Value; return reference; } if (targetType.IsArray || typeof(IList).IsAssignableFrom(targetType)) return ProcessArrayField(targetType, element); if (targetType.IsEnum) return Enum.Parse(targetType, element.Value); return Convert.ChangeType(element.Value, targetType); } /// /// 处理数组字段。 /// /// 字段类型。 /// XElement 元素。 /// 处理后的数组对象。 private static object ProcessArrayField(Type fieldType, XElement element) { // 获取集合的元素类型 var elementType = fieldType.IsArray ? fieldType.GetElementType() : fieldType.GetGenericArguments().FirstOrDefault(); if (elementType == null) { Debug.LogWarning($"无法确定类型为 {fieldType.Name} 的集合字段的元素类型。"); return null; } var arrayElements = new List(); // 遍历 XML 子元素 foreach (var liElement in element.Elements()) arrayElements.Add(ConvertXElementValueToType(liElement, elementType)); // 根据目标字段的类型构造结果 if (fieldType.IsArray) { var resultArray = Array.CreateInstance(elementType, arrayElements.Count); for (var i = 0; i < arrayElements.Count; i++) resultArray.SetValue(arrayElements[i], i); return resultArray; } if (typeof(IList).IsAssignableFrom(fieldType)) { var listType = typeof(List<>).MakeGenericType(elementType); var resultList = (IList)Activator.CreateInstance(listType); foreach (var item in arrayElements) resultList.Add(item); return resultList; } return null; } /// /// 从 中查找指定根元素名称的文档。 /// /// XML 文档列表。 /// 目标根元素名称。 /// 符合条件的 XML 文档列表。 public static List FindDocumentsWithRootName(List xmlDocuments, string rootName) { 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"); 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("未找到定义。"); return sb.ToString(); } /// /// 检查字段的类型是否继承自指定的类(严格派生,不包括基类本身)。 /// /// 字段信息。 /// 要检查的基类类型。 /// 如果字段的类型是基类的严格派生类,则返回 true;否则返回 false。 public static bool IsFieldTypeInheritedFrom(FieldInfo field, Type baseType) { var fieldType = field.FieldType; // 严格派生:不包括基类本身 return fieldType != null && fieldType != baseType && baseType.IsAssignableFrom(fieldType); } /// /// 检查一个类型是否继承自指定的基类(严格派生,不包括基类本身)。 /// /// 要检查的类型。 /// 要检查的基类类型。 /// 如果类型是基类的严格派生类,则返回 true;否则返回 false。 public static bool IsTypeInheritedFrom(Type type, Type baseType) { return type != null && type != baseType && baseType.IsAssignableFrom(type); } } }