using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; // 引入 Task using Data; using Utils; namespace Managers { public class SkillTreeManager : Singleton, ILaunchManager, ISavableSingleton { // 用于缓存解锁技能树的 SkillTreeDef 列表,提高频繁访问的效率 private List _cachedUnlockedSkillTreesList; private Dictionary> _childrenOfNode; // 内部数据结构,用于高效查询和图遍历 private Dictionary _skillNodesByDefName; private Dictionary> _skillNodesByTag; private Dictionary> _skillNodesByFaction; public SkillTreeManager() { // 遵循不检查单例的原则,假定 SaveManager.Instance 始终可用。 SaveManager.Instance.RegisterSavable(this); } // 解锁技能树的 HashSet,由 Savable 属性标记,用于存档 [Savable] public HashSet UnlockedSkillTrees { get; set; } = new(); /// /// 获取所有已解锁的技能树定义列表。此列表是缓存的,性能高效。 /// public List UnlockedSkillTreesList => _cachedUnlockedSkillTreesList ?? RebuildUnlockedSkillTreesCache(); /// /// 指示管理器是否已完成初始化。 /// public bool Completed { get; set; } // 新增:实现 ILaunchManager 接口的 Completed 属性 public string StepDescription => "正在加载技能树"; /// /// 初始化技能树管理器,加载并解析所有技能树定义。 /// /// 一个表示异步操作完成的 Task。 public async Task Init() // 接口变更:方法签名变为 async Task { // 增加检查,防止重复初始化 if (Completed) return; // 遵循不检查单例的原则,假定 DefineManager.Instance 始终可用。 var allSkillTreeNodes = DefineManager.Instance.QueryDefinesByType(); // 1. 初始化字典 _skillNodesByDefName = new Dictionary(); _skillNodesByTag = new Dictionary>(); _skillNodesByFaction = new Dictionary>(); _childrenOfNode = new Dictionary>(); if (allSkillTreeNodes == null) { Completed = true; // 即使没有定义,也认为初始化流程已完成 return; } // 2. 填充基本查询字典 foreach (var node in allSkillTreeNodes) { if (string.IsNullOrEmpty(node.defName)) { // Log.Warning($"SkillTreeDef with empty defName found. Skipping."); continue; } if (!_skillNodesByDefName.TryAdd(node.defName, node)) { // Log.Error($"Duplicate SkillTreeDef defName '{node.defName}' found. Only the first one will be used."); continue; // 跳过此重复节点 } // 填充 _skillNodesByTag if (!string.IsNullOrEmpty(node.tag)) { if (!_skillNodesByTag.ContainsKey(node.tag)) _skillNodesByTag[node.tag] = new List(); _skillNodesByTag[node.tag].Add(node); } // 填充 _skillNodesByFaction // 假设 AffiliationDef 也有 defName 属性作为唯一标识 if (node.faction != null && !string.IsNullOrEmpty(node.faction.defName)) { if (!_skillNodesByFaction.ContainsKey(node.faction.defName)) _skillNodesByFaction[node.faction.defName] = new List(); _skillNodesByFaction[node.faction.defName].Add(node); } } // 3. 填充 _childrenOfNode 字典(构建父 -> 子关系) // 需要再次遍历,因为在填充 _skillNodesByDefName 之前,prerequisites 中的引用可能尚未完全解析。 foreach (var childNode in allSkillTreeNodes) if (childNode.prerequisites != null) foreach (var prerequisite in childNode.prerequisites) // 确保父节点在 _skillNodesByDefName 中存在,避免野指针或无效引用 if (prerequisite != null && _skillNodesByDefName.TryGetValue(prerequisite.defName, out var parentNode)) { if (!_childrenOfNode.ContainsKey(parentNode.defName)) _childrenOfNode[parentNode.defName] = new List(); _childrenOfNode[parentNode.defName].Add(childNode); } else if (prerequisite != null) { // 记录警告:prerequisites中引用的父节点找不到定义,可能是数据配置错误 // Log.Warning($"SkillTreeDef '{childNode.defName}' references unknown prerequisite '{prerequisite.defName}'."); } // 4. 初始化解锁技能树的缓存列表 RebuildUnlockedSkillTreesCache(); Completed = true; // 在所有初始化逻辑完成后设置 Completed 为 true // 由于 Init 方法内部当前没有真正的异步操作,不需要显式 await Task.CompletedTask; // 编译器会为同步的 async Task 方法自动生成一个已完成的 Task。 } /// /// 清空技能树管理器加载的所有数据结构。 /// public void Clear() { // 清理所有数据结构,释放内存 _skillNodesByDefName?.Clear(); _skillNodesByTag?.Clear(); _skillNodesByFaction?.Clear(); _childrenOfNode?.Clear(); // 清理解锁技能树的缓存列表 _cachedUnlockedSkillTreesList?.Clear(); _cachedUnlockedSkillTreesList = null; // 将引用设为null,有助于GC _skillNodesByDefName = null; _skillNodesByTag = null; _skillNodesByFaction = null; _childrenOfNode = null; // 重要:UnlockedSkillTrees 是 Savable 属性,它的状态由 SaveManager 管理, // 通常不应在 Clear 方法中清空。Clear 仅清理运行时数据结构。 Completed = false; // 清理后将 Completed 置为 false } /// /// 当一个技能树被成功解锁时触发。 /// public event Action OnSkillTreeUnlocked; /// /// 当一个技能树被成功锁定时触发。 /// public event Action OnSkillTreeLocked; /// /// 根据当前 UnlockedSkillTrees 集合重建解锁技能树的缓存列表。 /// private List RebuildUnlockedSkillTreesCache() { // 在尝试查询技能定义之前,确保 _skillNodesByDefName 字典已初始化。 // 这可以防止在 Init() 尚未完全完成时访问缓存导致的空引用问题。 if (_skillNodesByDefName == null) { // 返回空列表是更温和的处理方式,表示目前没有可用的技能定义。 _cachedUnlockedSkillTreesList = new List(); return _cachedUnlockedSkillTreesList; } _cachedUnlockedSkillTreesList = new List(UnlockedSkillTrees.Count); // 预分配容量 foreach (var skillTreeDefName in UnlockedSkillTrees) if (_skillNodesByDefName.TryGetValue(skillTreeDefName, out var skillDef) && skillDef != null) _cachedUnlockedSkillTreesList.Add(skillDef); return _cachedUnlockedSkillTreesList; } // --- 节点查询 --- /// /// 根据定义名查询技能树节点 /// /// 技能树节点的定义名 /// 匹配的 SkillTreeDef,如果未找到则为 null public SkillTreeDef GetNodeByDefName(string defName) { if (string.IsNullOrEmpty(defName)) return null; _skillNodesByDefName.TryGetValue(defName, out var node); return node; } /// /// 根据标签查询技能树节点列表 /// /// 技能树节点的标签 /// 匹配的 SkillTreeDef 列表,如果未找到则返回空列表 public List GetNodesByTag(string tag) { if (string.IsNullOrEmpty(tag)) return new List(); _skillNodesByTag.TryGetValue(tag, out var nodes); return nodes ?? new List(); } /// /// 根据派系名称查询技能树节点列表 /// /// 派系的定义名 /// 匹配的 SkillTreeDef 列表,如果未找到则返回空列表 public List GetNodesByFaction(string factionName) { if (string.IsNullOrEmpty(factionName)) return new List(); _skillNodesByFaction.TryGetValue(factionName, out var nodes); return nodes ?? new List(); } public string[] GetAllTag() { return _skillNodesByTag.Keys.ToArray(); } // --- 父子关系查询 --- /// /// 判断 targetNode 是否是 baseNode 的直接父节点 /// /// 作为父节点候选的节点 /// 作为子节点候选的节点 /// 如果是直接父节点则为 true,否则为 false public bool IsDirectParentOf(SkillTreeDef baseNode, SkillTreeDef targetNode) { if (baseNode == null || targetNode == null || targetNode.prerequisites == null) return false; return targetNode.prerequisites.Any(prerequisite => prerequisite != null && prerequisite.defName == baseNode.defName); } /// /// 判断 targetNode 是否是 baseNode 的直接子节点 /// /// 作为父节点的节点 /// 作为子节点候选的节点 /// 如果是直接子节点则为 true,否则为 false public bool IsDirectChildOf(SkillTreeDef baseNode, SkillTreeDef targetNode) { if (baseNode == null || targetNode == null) return false; // 查找 baseNode 的子节点列表中是否包含 targetNode _childrenOfNode.TryGetValue(baseNode.defName, out var children); return children != null && children.Any(c => c.defName == targetNode.defName); } /// /// 判断 ancestor 是否是 descendant 的任何一级父节点(包括直接和间接) /// /// 祖先节点候选 /// 后代节点候选 /// 如果是祖先节点则为 true,否则为 false public bool IsAncestorOf(SkillTreeDef ancestor, SkillTreeDef descendant) { if (ancestor == null || descendant == null) return false; if (ancestor.defName == descendant.defName) return false; // 自己不是自己的祖先 return GetAllAncestors(descendant).Any(n => n.defName == ancestor.defName); } /// /// 判断 descendant 是否是 ancestor 的任何一级子节点(包括直接和间接) /// /// 后代节点候选 /// 祖先节点候选 /// 如果是后代节点则为 true,否则为 false public bool IsDescendantOf(SkillTreeDef descendant, SkillTreeDef ancestor) { if (descendant == null || ancestor == null) return false; if (descendant.defName == ancestor.defName) return false; // 自己不是自己的后代 return GetAllDescendants(ancestor).Any(n => n.defName == descendant.defName); } // --- 获取所有相关节点 --- /// /// 获取所有直接父节点 /// /// 要查询的节点 /// 直接父节点列表,如果无父节点则返回空列表 public List GetAllDirectParents(SkillTreeDef node) { if (node?.prerequisites == null) return new List(); // 确保返回的是真实存在于管理器中的节点,而不是可能无效的引用 return node.prerequisites.Where(p => p != null && _skillNodesByDefName.ContainsKey(p.defName)) .Select(p => _skillNodesByDefName[p.defName]) .ToList(); } /// /// 获取所有直接子节点 /// /// 要查询的节点 /// 直接子节点列表,如果无子节点则返回空列表 public List GetAllDirectChildren(SkillTreeDef node) { if (node == null) return new List(); _childrenOfNode.TryGetValue(node.defName, out var children); return children ?? new List(); } /// /// 获取所有祖先节点(包括直接和间接父节点),使用 BFS 算法避免循环依赖 /// /// 要查询的节点 /// 所有祖先节点列表 public List GetAllAncestors(SkillTreeDef node) { if (node == null) return new List(); var ancestors = new HashSet(); // 使用HashSet避免重复和循环 var queue = new Queue(); // 将当前节点的直接父节点作为起点加入队列 if (node.prerequisites != null) foreach (var directParentRef in node.prerequisites) if (directParentRef != null && _skillNodesByDefName.TryGetValue(directParentRef.defName, out var parentNode)) if (!ancestors.Contains(parentNode)) { ancestors.Add(parentNode); queue.Enqueue(parentNode); } while (queue.Count > 0) { var current = queue.Dequeue(); if (current.prerequisites != null) foreach (var prerequisiteRef in current.prerequisites) if (prerequisiteRef != null && _skillNodesByDefName.TryGetValue(prerequisiteRef.defName, out var actualParentNode)) if (!ancestors.Contains(actualParentNode)) { ancestors.Add(actualParentNode); queue.Enqueue(actualParentNode); } } return ancestors.ToList(); } /// /// 获取所有后代节点(包括直接和间接子节点),使用 BFS 算法避免循环依赖 /// /// 要查询的节点 /// 所有后代节点列表 public List GetAllDescendants(SkillTreeDef node) { if (node == null) return new List(); var descendants = new HashSet(); // 使用HashSet避免重复和循环 var queue = new Queue(); // 将当前节点的直接子节点作为起点加入队列 _childrenOfNode.TryGetValue(node.defName, out var directChildren); if (directChildren != null) foreach (var child in directChildren) if (!descendants.Contains(child)) { descendants.Add(child); queue.Enqueue(child); } while (queue.Count > 0) { var current = queue.Dequeue(); _childrenOfNode.TryGetValue(current.defName, out var children); if (children != null) foreach (var child in children) if (!descendants.Contains(child)) { descendants.Add(child); queue.Enqueue(child); } } return descendants.ToList(); } /// /// 获取指定名称的技能树定义,如果名称无效或未找到,则抛出 ArgumentException。 /// /// 要获取的技能树定义名称。 /// 对应的 SkillTreeDef 对象。 /// 如果 skillTreeDefName 为空或未找到对应的 SkillTreeDef。 private SkillTreeDef GetValidSkillTreeDef(string skillTreeDefName) { // `TryGetValue` 成功但 `node` 仍为null理论上不发生,但为安全起见 if (string.IsNullOrEmpty(skillTreeDefName) || !_skillNodesByDefName.TryGetValue(skillTreeDefName, out var node) || node == null) throw new ArgumentException($"Invalid or unknown SkillTreeDef name: '{skillTreeDefName}'.", nameof(skillTreeDefName)); return node; } /// /// 尝试解锁一个技能树。 /// 必须是有效的 skillTreeDefName,否则会抛出 ArgumentException。 /// /// 要解锁的技能树的定义名称。 /// 如果技能树成功解锁(之前未解锁),则为 true;如果技能树已经解锁,则为 false。 /// 如果 skillTreeDefName 无效。 public bool UnlockSkillTree(string skillTreeDefName) { var skillDef = GetValidSkillTreeDef(skillTreeDefName); // 使用新的验证方法,如果无效会抛出异常 if (UnlockedSkillTrees.Add(skillTreeDefName)) { RebuildUnlockedSkillTreesCache(); // 技能树状态改变,重建缓存 OnSkillTreeUnlocked?.Invoke(skillDef); // 触发解锁事件 return true; } return false; } /// /// 尝试加锁(锁定)一个技能树。 /// 必须是有效的 skillTreeDefName,否则会抛出 ArgumentException。 /// /// 要加锁的技能树的定义名称。 /// 如果技能树成功加锁(之前已解锁),则为 true;如果技能树已经加锁,则为 false。 /// 如果 skillTreeDefName 无效。 public bool LockSkillTree(string skillTreeDefName) { var skillDef = GetValidSkillTreeDef(skillTreeDefName); // 使用新的验证方法,如果无效会抛出异常 if (UnlockedSkillTrees.Remove(skillTreeDefName)) { RebuildUnlockedSkillTreesCache(); // 技能树状态改变,重建缓存 OnSkillTreeLocked?.Invoke(skillDef); // 触发锁定事件 return true; } return false; } /// /// 查询指定技能树是否已解锁。 /// 必须是有效的 skillTreeDefName,否则会抛出 ArgumentException。 /// /// 要查询的技能树的定义名称。 /// 如果技能树已解锁,则为 true;否则为 false。 /// 如果 skillTreeDefName 无效。 public bool IsSkillTreeUnlocked(string skillTreeDefName) { // GetValidSkillTreeDef 会在 defName 无效时抛出 ArgumentException // 如果成功返回,说明 skillTreeDefName 是有效的 GetValidSkillTreeDef(skillTreeDefName); return UnlockedSkillTrees.Contains(skillTreeDefName); } } }