Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Managers/DefineManager.cs

499 lines
19 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 Data;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Utils;
namespace Managers
{
/// <summary>
/// 定义管理器负责加载、管理和查询所有数据定义Define对象。
/// </summary>
/// <remarks>
/// 该管理器是一个单例,用于在应用程序中集中管理各种游戏或系统定义,
/// 包括从不同数据包Mods加载定义处理定义之间的引用以及提供多种查询方法。
/// </remarks>
public class DefineManager : Singleton<DefineManager>, ILaunchManager
{
/// <summary>
/// 数据集文件路径数组,用于指定定义包的根目录。
/// </summary>
private static readonly string[] dataSetFilePath = { "Data", "Mods" };
/// <summary>
/// 存储所有按类别和定义名索引的定义。
/// </summary>
/// <remarks>
/// 外层字典的键是定义类别(例如,类的类型名),内层字典的键是定义的名称。
/// </remarks>
public Dictionary<string, Dictionary<string, Define>> defines = new();
/// <summary>
/// 存储所有按包ID索引的定义包。
/// </summary>
/// <remarks>
/// 键是定义包的唯一ID值是对应的 <see cref="DefinePack"/> 对象。
/// </remarks>
public Dictionary<string, DefinePack> packs = new();
/// <summary>
/// 存储所有按类别索引的匿名定义列表。
/// </summary>
/// <remarks>
/// 匿名定义是没有明确 <see cref="Define.defName"/> 的定义,它们通常作为其他定义的子元素出现。
/// 外层字典的键是定义类别,值是该类别下的匿名定义列表。
/// </remarks>
public Dictionary<string, List<Define>> anonymousDefines = new();
public string StepDescription => "加载数据定义中";
/// <summary>
/// 初始化定义管理器,加载所有定义包并构建定义字典。
/// </summary>
/// <remarks>
/// 该方法执行以下操作:
/// <list type="number">
/// <item>获取指定路径下的所有子文件夹,每个子文件夹代表一个定义包。</item>
/// <item>遍历每个定义包,尝试加载其中的定义数据。</item>
/// <item>将加载的定义数据按类型分类,并存储到定义字典中。</item>
/// <item>处理定义内部的引用关系,将引用占位符替换为实际定义对象。</item>
/// </list>
/// </remarks>
public void Init()
{
if (packs.Count > 0)
return;
// 获取所有定义包的文件夹路径
var packFolder = Configs.ConfigProcessor.GetSubFolders(new(dataSetFilePath));
foreach (var folder in packFolder)
{
var pack = new DefinePack();
if (pack.LoadPack(folder))
{
packs.Add(pack.packID, pack);
}
}
// 字段信息缓存,用于优化反射性能。
Dictionary<Type, FieldInfo[]> fieldCache = new();
// 存储需要进行链接的定义引用信息。
// Tuple的元素依次代表被引用的定义Define引用该定义的字段FieldInfo以及引用占位符Define
List<Tuple<Define, FieldInfo, Define>> defineCache = new();
string currentPackID;
// 递归处理定义对象及其内部的嵌套定义和引用。
void ProcessDefine(Define def)
{
if (def == null || def.isReferene)
return;
def.packID = currentPackID;
// 检查是否已缓存字段信息,如果已缓存则直接使用。
if (!fieldCache.TryGetValue(def.GetType(), out var defineFields))
{
// 获取所有公共实例字段。
defineFields = def.GetType()
.GetFields(BindingFlags.Public | BindingFlags.Instance);
// 缓存当前类型的字段信息。
fieldCache[def.GetType()] = defineFields;
}
foreach (var defineField in defineFields)
{
var fieldType = defineField.FieldType;
// 处理单个 Define 类型的字段
if (typeof(Define).IsAssignableFrom(fieldType))
{
var defRef = (Define)defineField.GetValue(def);
if (defRef == null)
continue;
if (defRef.isReferene)
{
defineCache.Add(new Tuple<Define, FieldInfo, Define>(def, defineField, defRef));
}
else
{
if (string.IsNullOrEmpty(defRef.defName))
{
var typeName = defRef.GetType().Name;
if (!anonymousDefines.ContainsKey(typeName))
anonymousDefines.Add(typeName, new List<Define>());
anonymousDefines[typeName].Add(defRef);
}
ProcessDefine(defRef);
}
}
// 处理 List<Define> 类型的字段
else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>))
{
var elementType = fieldType.GenericTypeArguments[0];
if (typeof(Define).IsAssignableFrom(elementType))
{
var list = (IList)defineField.GetValue(def);
if (list != null)
{
foreach (var item in list)
{
if (item is Define { isReferene: false } defItem)
{
ProcessDefine(defItem);
}
}
}
}
}
// 处理 Define[] 类型的数组字段
else if (fieldType.IsArray)
{
var elementType = fieldType.GetElementType();
if (typeof(Define).IsAssignableFrom(elementType))
{
var array = (Array)defineField.GetValue(def);
if (array != null)
{
foreach (var item in array)
{
if (item is Define { isReferene: false } defItem)
{
ProcessDefine(defItem);
}
}
}
}
}
}
}
foreach (var pack in packs)
{
currentPackID = pack.Value.packID;
foreach (var (typeName, defList) in pack.Value.defines)
{
if (!defines.ContainsKey(typeName))
defines[typeName] = new Dictionary<string, Define>();
foreach (var def in defList)
{
defines[typeName][def.defName] = def;
ProcessDefine(def);
}
}
}
// 处理所有定义间的引用关系
foreach (var defRef in defineCache)
{
if (defRef.Item1 == null)
{
Debug.LogError("被引用定义为 null");
continue;
}
if (defRef.Item2 == null)
{
Debug.LogError("被引用定义的字段引用为 null");
continue;
}
var value = FindDefine(defRef.Item3.description, defRef.Item3.defName);
if (value == null)
{
Debug.LogError($"未找到引用,出错的定义:定义类型:{defRef.Item1.GetType().Name}, 定义名:{defRef.Item1.defName} ; 类型:{defRef.Item3.description}, 定义名:{defRef.Item3.defName}");
continue;
}
try
{
defRef.Item2.SetValue(defRef.Item1, value);
}
catch (Exception ex)
{
Debug.LogError($"SetValue 出错: {ex.Message}");
}
}
}
public void Clear()
{
defines.Clear();
packs.Clear();
anonymousDefines.Clear();
}
/// <summary>
/// 查找指定定义类型的定义名对应的 <see cref="Define"/> 对象。
/// </summary>
/// <param name="defineType">定义类型(通常是类的名称)。</param>
/// <param name="defineName">定义名。</param>
/// <returns>如果找到,返回 <see cref="Define"/> 对象;否则返回 null。</returns>
public Define FindDefine(string defineType, string defineName)
{
if (defines.TryGetValue(defineType, out var typeDict))
{
if (typeDict.TryGetValue(defineName, out var define))
{
return define;
}
}
return null;
}
/// <summary>
/// 使用泛型模板查找并返回指定类型的 <see cref="Define"/> 对象。
/// </summary>
/// <typeparam name="T">目标类型,必须继承自 <see cref="Define"/>。</typeparam>
/// <param name="defineName">定义名。</param>
/// <returns>如果找到,返回转换为目标类型的 <see cref="Define"/> 对象;否则返回 null。</returns>
public T FindDefine<T>(string defineName) where T : Define
{
if (defines.TryGetValue(typeof(T).Name, out var typeDict))
{
if (typeDict.TryGetValue(defineName, out var define))
{
return (T)define;
}
}
return null;
}
/// <summary>
/// 获取指定 <see cref="Define"/> 对象所属的定义包。
/// </summary>
/// <param name="define">要查询的 <see cref="Define"/> 对象。</param>
/// <returns>如果找到对应的定义包,则返回 <see cref="DefinePack"/> 对象;否则返回 null。</returns>
public DefinePack GetDefinePackage(Define define)
{
if (define == null || define.packID == null)
return null;
packs.TryGetValue(define.packID, out var pack);
return pack;
}
/// <summary>
/// 获取指定 <see cref="Define"/> 对象所属定义包的名称。
/// </summary>
/// <param name="define">要查询的 <see cref="Define"/> 对象。</param>
/// <returns>如果找到对应的定义包,则返回其名称;否则返回 null。</returns>
public string GetDefinePackageName(Define define)
{
return GetDefinePackage(define)?.Name;
}
/// <summary>
/// 获取指定包ID对应定义包的根路径。
/// </summary>
/// <param name="packID">定义包的唯一标识ID。</param>
/// <returns>如果找到对应的定义包,则返回其根路径;否则返回 null。</returns>
public string GetPackagePath(string packID)
{
if (packs.TryGetValue(packID, out var pack))
{
return pack.packRootPath;
}
return null;
}
/// <summary>
/// 获取所有已加载的 <see cref="Define"/> 对象。
/// </summary>
/// <returns>包含所有命名定义和匿名定义的数组。</returns>
public Define[] GetAllDefine()
{
List<Define> defineList = new();
foreach (var define in defines.Values)
{
defineList.AddRange(define.Values);
}
foreach (var anonymousDefine in anonymousDefines)
{
defineList.AddRange(anonymousDefine.Value);
}
return defineList.ToArray();
}
/// <summary>
/// 查询指定类型下的所有 <see cref="Define"/> 对象(包括命名定义和匿名定义)。
/// </summary>
/// <param name="defineType">定义类型(外层字典的键,通常是类的名称)。</param>
/// <returns>该类型下的 <see cref="Define"/> 数组。如果未找到任何定义,则返回 null。</returns>
public Define[] QueryDefinesByType(string defineType)
{
if (string.IsNullOrEmpty(defineType))
{
Debug.LogError("查询失败:定义类型参数不能为空!");
return null;
}
var result = new List<Define>();
// 从命名定义中查询。
if (defines.TryGetValue(defineType, out var namedDefinitions))
{
result.AddRange(namedDefinitions.Values);
}
// 从匿名定义中查询。
if (anonymousDefines.TryGetValue(defineType, out var anonymousDefinitionList))
{
result.AddRange(anonymousDefinitionList);
}
// 如果结果为空,则返回 null。
if (result.Count == 0)
{
Debug.LogWarning($"查询失败:未找到定义类型 '{defineType}'");
return null;
}
return result.ToArray();
}
/// <summary>
/// 查询指定类型下的所有 <see cref="Define"/> 对象,并尝试转换为目标类型(包括命名定义和匿名定义)。
/// </summary>
/// <typeparam name="T">目标类型,必须继承自 <see cref="Define"/>。</typeparam>
/// <returns>转换后的目标类型数组。如果未找到或转换失败,则返回 null。</returns>
public T[] QueryDefinesByType<T>() where T : Define
{
var defineType = typeof(T).Name;
var allDefines = QueryDefinesByType(defineType)?.ToList();
if (allDefines == null || allDefines.Count == 0)
{
return null;
}
try
{
// 尝试将所有 <see cref="Define"/> 对象转换为目标类型 T。
var result = new List<T>();
foreach (var item in allDefines)
{
if (item is T converted)
{
result.Add(converted);
}
else
{
Debug.LogError($"类型转换失败:无法将 {item.GetType().Name} 转换为 {typeof(T).Name}");
return null;
}
}
return result.ToArray();
}
catch (Exception ex)
{
Debug.LogError($"类型转换失败:从 Define 转换为 {typeof(T).Name} 时出错。错误信息:{ex.Message}");
return null;
}
}
/// <summary>
/// 查询指定类型下的所有命名 <see cref="Define"/> 对象(不包括匿名定义)。
/// </summary>
/// <param name="defineType">定义类型(外层字典的键,通常是类的名称)。</param>
/// <returns>该类型下的命名 <see cref="Define"/> 数组。如果未找到任何命名定义,则返回 null。</returns>
public Define[] QueryNamedDefinesByType(string defineType)
{
if (string.IsNullOrEmpty(defineType))
{
Debug.LogError("查询失败:定义类型参数不能为空!");
return null;
}
var result = new List<Define>();
// 仅从命名定义中查询。
if (defines.TryGetValue(defineType, out var namedDefinitions))
{
result.AddRange(namedDefinitions.Values);
}
// 如果结果为空,则返回 null。
if (result.Count == 0)
{
Debug.LogWarning($"查询失败:未找到定义类型 '{defineType}' 的命名定义");
return null;
}
return result.ToArray();
}
/// <summary>
/// 查询指定类型下的所有命名 <see cref="Define"/> 对象,并尝试转换为目标类型(不包括匿名定义)。
/// </summary>
/// <typeparam name="T">目标类型,必须继承自 <see cref="Define"/>。</typeparam>
/// <returns>转换后的目标类型数组。如果未找到或转换失败,则返回 null。</returns>
public T[] QueryNamedDefinesByType<T>() where T : Define
{
var defineType = typeof(T).Name;
var allDefines = QueryNamedDefinesByType(defineType)?.ToList();
if (allDefines == null || allDefines.Count == 0)
{
return null;
}
try
{
// 尝试将所有 <see cref="Define"/> 对象转换为目标类型 T。
var result = new List<T>();
foreach (var item in allDefines)
{
if (item is T converted)
{
result.Add(converted);
}
else
{
Debug.LogError($"类型转换失败:无法将 {item.GetType().Name} 转换为 {typeof(T).Name}");
return null;
}
}
return result.ToArray();
}
catch (Exception ex)
{
Debug.LogError($"类型转换失败:从 Define 转换为 {typeof(T).Name} 时出错。错误信息:{ex.Message}");
return null;
}
}
/// <summary>
/// 返回所有加载的定义包的字符串表示。
/// </summary>
/// <returns>一个包含所有定义包信息的字符串,每个包信息占一行。</returns>
public override string ToString()
{
if (packs == null || packs.Count == 0)
{
// 如果集合为空或为 null返回默认信息。
return "No packs available";
}
var result = new System.Text.StringBuilder();
foreach (var definePack in packs)
{
// 每个定义包对象占一行。
result.AppendLine(definePack.ToString());
}
return result.ToString();
}
}
}