Story流程+本地化

This commit is contained in:
SoulliesOfficial
2026-07-24 17:56:30 -04:00
parent b0e0a7d5aa
commit de70870682
250 changed files with 5719 additions and 272966 deletions

View File

@@ -63,11 +63,6 @@ namespace Ichni.Story
issues.Add("[Warning] Yarn Project 未配置TextBlock 无法开始对应的 Yarn 节点。");
}
if (yarnLineStringTable == null || yarnLineStringTable.IsEmpty)
{
issues.Add("[Error] Yarn Line String Table 未配置Player 中无法在启动对话前加载当前 Locale 的台词表。");
}
foreach (StoryVariableDefinition variable in initialVariables)
{
if (variable == null)
@@ -121,6 +116,7 @@ namespace Ichni.Story
}
ValidateTextBlockYarnNodes(issues);
ValidateUniqueSongBlockIds(issues);
HashSet<string> reachableBlockIds = ValidateStoryGraph(blockIds, issues);
foreach (StoryTimelineMarkerDefinition marker in timelineMarkers)
@@ -262,6 +258,43 @@ namespace Ichni.Story
/// 对 StoryData 的连接图做只读的结构检查:入口、不可达 Block、环路、非向前连接与终点。
/// 这些检查不评价具体剧情质量,只定位最容易造成“永远无法游玩”或“无法结束章节”的配置问题。
/// </summary>
/// <summary>
/// SongSelection -> Story 的定向入口以 SongItemData.songName 匹配 SongBlock.songName。
/// 同一章节内重复配置同一 Song ID 时,运行时只能按列表顺序定位第一个 Block
/// 因此在编辑阶段输出 Warning让配置者消除这个导航歧义。
/// </summary>
private void ValidateUniqueSongBlockIds(List<string> issues)
{
Dictionary<string, List<string>> blockIdsBySongId = new Dictionary<string, List<string>>();
foreach (StoryBlockDefinition block in blocks)
{
if (block == null || block.blockType != StoryBlockType.Song ||
string.IsNullOrWhiteSpace(block.songName))
{
continue;
}
if (!blockIdsBySongId.TryGetValue(block.songName, out List<string> referencedBlocks))
{
referencedBlocks = new List<string>();
blockIdsBySongId[block.songName] = referencedBlocks;
}
referencedBlocks.Add(block.blockId);
}
foreach (KeyValuePair<string, List<string>> pair in blockIdsBySongId)
{
if (pair.Value.Count <= 1)
continue;
issues.Add(
$"[Warning] Song ID '{pair.Key}' 被多个 SongBlock 引用({string.Join(", ", pair.Value)})。" +
"SongSelection -> Story 只能定位列表中的第一个 Block请保留每章每首歌唯一的 SongBlock。"
);
}
}
private HashSet<string> ValidateStoryGraph(HashSet<string> blockIds, List<string> issues)
{
Dictionary<string, List<string>> adjacency = new Dictionary<string, List<string>>();

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Localization;
using Yarn.Unity;
namespace Ichni.Story
@@ -23,11 +22,6 @@ namespace Ichni.Story
[Tooltip("该章节对应的 YarnProject 编译资产。TextBlock 会在运行时从此项目中执行配置的 Yarn Node。")]
public YarnProject yarnProject;
[TitleGroup("Chapter Settings")]
[LabelText("Yarn Line String Table")]
[Tooltip("该章节 Yarn 台词对应的 Unity Localization String Table。运行时会在启动对话前显式加载当前 Locale 的表;此配置必须与 DialogueRunner 上 UnityLocalisedLineProvider 使用的表一致。")]
public LocalizedStringTable yarnLineStringTable;
/// <summary>
/// 本章节永久剧情变量的默认值。它们只属于本章节,且不会直接写入存档;
/// 玩家第一次通过 Yarn 或其它剧情入口写入同名变量后,存档值才会覆盖这里的默认值。