Files
aibis-dream/Assets/Scripts/Game Loop/TalkSceneGraphIndex.cs
T

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);
}
}
}