99 lines
2.9 KiB
C#
99 lines
2.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace AibisDream
|
|
{
|
|
/// <summary>
|
|
/// 从现有 TalkSceneSO 图派生的运行时索引,不引入第二份章节创作数据。
|
|
/// </summary>
|
|
public sealed class TalkSceneGraphIndex
|
|
{
|
|
private readonly List<TalkSceneSO> _runtimeChapters = new();
|
|
private readonly Dictionary<string, TalkSceneSO> _byName = new(StringComparer.Ordinal);
|
|
private readonly HashSet<string> _ambiguousNames = new(StringComparer.Ordinal);
|
|
private readonly List<string> _validationErrors = new();
|
|
|
|
public IReadOnlyList<TalkSceneSO> RuntimeChapters => _runtimeChapters;
|
|
public IReadOnlyList<string> ValidationErrors => _validationErrors;
|
|
|
|
public TalkSceneGraphIndex(TalkSceneSO firstTalkScene)
|
|
{
|
|
var visited = new HashSet<TalkSceneSO>();
|
|
VisitRuntime(firstTalkScene, visited);
|
|
}
|
|
|
|
public bool TryFindByName(string sceneName, out TalkSceneSO scene, out string error)
|
|
{
|
|
scene = null;
|
|
if (string.IsNullOrWhiteSpace(sceneName))
|
|
{
|
|
error = "TalkSceneSO name is empty.";
|
|
return false;
|
|
}
|
|
|
|
if (_ambiguousNames.Contains(sceneName))
|
|
{
|
|
error = $"TalkSceneSO name is ambiguous: {sceneName}.";
|
|
return false;
|
|
}
|
|
|
|
if (!_byName.TryGetValue(sceneName, out scene) || scene == null)
|
|
{
|
|
error = $"TalkSceneSO does not exist: {sceneName}.";
|
|
return false;
|
|
}
|
|
|
|
error = null;
|
|
return true;
|
|
}
|
|
|
|
private void VisitRuntime(TalkSceneSO scene, ISet<TalkSceneSO> visited)
|
|
{
|
|
if (scene == null || !visited.Add(scene))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_runtimeChapters.Add(scene);
|
|
IndexByName(scene);
|
|
|
|
if (scene.exits == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var exit in scene.exits)
|
|
{
|
|
VisitRuntime(exit?.targetScene, visited);
|
|
}
|
|
}
|
|
|
|
private void IndexByName(TalkSceneSO scene)
|
|
{
|
|
if (scene == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var sceneName = scene.name;
|
|
if (string.IsNullOrWhiteSpace(sceneName))
|
|
{
|
|
_validationErrors.Add("TalkSceneSO has an empty asset name.");
|
|
return;
|
|
}
|
|
|
|
if (_byName.TryGetValue(sceneName, out var existing))
|
|
{
|
|
if (existing != scene && _ambiguousNames.Add(sceneName))
|
|
{
|
|
_validationErrors.Add($"Duplicate TalkSceneSO name: {sceneName}.");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
_byName.Add(sceneName, scene);
|
|
}
|
|
}
|
|
}
|