using System; using System.Collections.Generic; using System.Linq; using AibisDream.Kit; using AibisDream.SaveSystem; using UnityEngine; namespace AibisDream.FixSystem { /// /// 打孔带系统入口:收藏数据、Yarn 命令、弹窗与收藏夹面板代理。 /// public class PunchTapeManager : Singleton { public GameObject punchTapecluePrefab; [SerializeField] private PunchTapeCatalog punchTapeCatalog; public PunchTapeCatalog Catalog => punchTapeCatalog; [SerializeField] private PunchTapeFavoritesPanel favoritesPanel; public PunchTapeFavoritesPanel FavoritesPanel => favoritesPanel; [SerializeField] private PunchTapePrinter punchTapePrinter; public PunchTapePrinter PunchTapePrinter => punchTapePrinter; private readonly List _favorites = new(); private GameObject currentPunchTapeGO; /// 收藏列表变更时通知 等订阅方。 public event Action OnCollectionChanged; public IReadOnlyList GetFavorites() { return _favorites; } public PunchTapeSnapshotDto CapturePunchTapeSnapshot() { return new PunchTapeSnapshotDto { favorites = _favorites.Select(t => new PunchTape(t.DefinitionId) { used = t.used }).ToList() }; } public void ApplyPunchTapeSnapshot(PunchTapeSnapshotDto dto) { _favorites.Clear(); if (dto?.favorites != null) { foreach (var tape in dto.favorites) { if (!TryGetDefinition(tape, out _)) { Debug.LogWarning( $"[PunchTapeManager] 存档中的打孔带 ID '{tape?.DefinitionId ?? ""}' 无法解析,已跳过。", this); continue; } if (!_favorites.Contains(tape)) _favorites.Add(tape); } } OnCollectionChanged?.Invoke(); } public void AddPunchTape(PunchTape punchTape) { if (punchTape == null) return; if (!TryGetDefinition(punchTape, out _)) { Debug.LogError($"[PunchTapeManager] 无法收藏未知打孔带 '{punchTape.DefinitionId}'。", this); return; } if (_favorites.Contains(punchTape)) return; _favorites.Add(punchTape); OnCollectionChanged?.Invoke(); } public void RemovePunchTape(PunchTape punchTape) { if (punchTape == null) return; if (!_favorites.Remove(punchTape)) return; OnCollectionChanged?.Invoke(); } public void OpenFavoritesPanel() { if (favoritesPanel == null) { Debug.LogWarning("[PunchTapeManager] 未指定 _favoritesPanel,无法打开收藏夹面板。", this); return; } favoritesPanel.OpenPanel(); } public void CloseFavoritesPanel() { if (favoritesPanel == null) { Debug.LogWarning("[PunchTapeManager] 未指定 _favoritesPanel,无法关闭收藏夹面板。", this); return; } favoritesPanel.ClosePanel(); } public bool TryGetDefinition(string definitionId, out PunchTapeDefinition definition) { definition = null; if (punchTapeCatalog == null) { Debug.LogError("[PunchTapeManager] 未配置 PunchTapeCatalog。", this); return false; } var catalogErrors = punchTapeCatalog.GetValidationErrors(); if (catalogErrors.Count > 0) { Debug.LogError( $"[PunchTapeManager] PunchTapeCatalog 配置无效:\n{string.Join("\n", catalogErrors)}", this); return false; } if (!punchTapeCatalog.TryGetDefinition(definitionId, out definition)) { Debug.LogError($"[PunchTapeManager] 未找到打孔带 ID '{definitionId}'。", this); definition = null; return false; } if (!definition.TryValidate(out var error)) { Debug.LogError($"[PunchTapeManager] 打孔带 ID '{definitionId}' 无效:{error}", this); definition = null; return false; } return true; } public bool TryGetDefinition(PunchTape punchTape, out PunchTapeDefinition definition) { return TryGetDefinition(punchTape?.DefinitionId, out definition); } public void GeneratePunchTapeWindow(string definitionId, bool directlyAddToFavorites = false) { if (!TryGetDefinition(definitionId, out var definition)) return; PunchTape punchTape = new PunchTape(definitionId); if (directlyAddToFavorites) { AddPunchTape(punchTape); return; } GameObject go = Instantiate(punchTapecluePrefab, favoritesPanel.transform); PunchTapeItem item = go.GetComponent(); if (item == null) { Debug.LogError("[PunchTapeManager] 生成 Prefab 缺少 PunchTapeItem。", go); Destroy(go); return; } currentPunchTapeGO = go; item.Setup(punchTape, definition); } /// /// 将当前弹窗中的打孔带收入收藏。兼容旧 Yarn:<<CollectionClue ClueManager>> 会传入参数,仍应执行收藏。 /// public void CollectPunchTapeFromWindow() { if (currentPunchTapeGO == null) { Debug.LogWarning("PunchTapeManager: 没有当前打孔带窗口,无法收藏。"); return; } PunchTapeItem item = currentPunchTapeGO.GetComponent(); if (item == null) { Debug.LogWarning("PunchTapeManager: 当前物体上缺少 PunchTapeItem。"); return; } AddPunchTape(item.GetPunchTapeData()); Destroy(currentPunchTapeGO.gameObject); currentPunchTapeGO = null; } } }