208 lines
6.7 KiB
C#
208 lines
6.7 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using AibisDream.Kit;
|
||
using AibisDream.SaveSystem;
|
||
using UnityEngine;
|
||
|
||
namespace AibisDream.FixSystem
|
||
{
|
||
/// <summary>
|
||
/// 打孔带系统入口:收藏数据、Yarn 命令、弹窗与收藏夹面板代理。
|
||
/// </summary>
|
||
public class PunchTapeManager : Singleton<PunchTapeManager>
|
||
{
|
||
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<PunchTape> _favorites = new();
|
||
|
||
private GameObject currentPunchTapeGO;
|
||
|
||
/// <summary>收藏列表变更时通知 <see cref="PunchTapeFavoritesPanel"/> 等订阅方。</summary>
|
||
public event Action OnCollectionChanged;
|
||
|
||
public IReadOnlyList<PunchTape> 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 ?? "<null>"}' 无法解析,已跳过。",
|
||
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<PunchTapeItem>();
|
||
if (item == null)
|
||
{
|
||
Debug.LogError("[PunchTapeManager] 生成 Prefab 缺少 PunchTapeItem。", go);
|
||
Destroy(go);
|
||
return;
|
||
}
|
||
|
||
currentPunchTapeGO = go;
|
||
item.Setup(punchTape, definition);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将当前弹窗中的打孔带收入收藏。兼容旧 Yarn:<<CollectionClue ClueManager>> 会传入参数,仍应执行收藏。
|
||
/// </summary>
|
||
public void CollectPunchTapeFromWindow()
|
||
{
|
||
if (currentPunchTapeGO == null)
|
||
{
|
||
Debug.LogWarning("PunchTapeManager: 没有当前打孔带窗口,无法收藏。");
|
||
return;
|
||
}
|
||
|
||
PunchTapeItem item = currentPunchTapeGO.GetComponent<PunchTapeItem>();
|
||
if (item == null)
|
||
{
|
||
Debug.LogWarning("PunchTapeManager: 当前物体上缺少 PunchTapeItem。");
|
||
return;
|
||
}
|
||
|
||
AddPunchTape(item.GetPunchTapeData());
|
||
Destroy(currentPunchTapeGO.gameObject);
|
||
currentPunchTapeGO = null;
|
||
}
|
||
}
|
||
}
|