阶段性完成

This commit is contained in:
SoulliesOfficial
2026-07-25 13:27:53 -04:00
parent de70870682
commit a34461d31f
121 changed files with 7022 additions and 4111 deletions

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Localization;
namespace Ichni.Story
{
@@ -147,9 +148,9 @@ namespace Ichni.Story
[FoldoutGroup("$EditorHeader/Text Content")]
[ShowIf("blockType", StoryBlockType.Text)]
[LabelText("Title Key")]
[Tooltip("该 TextBlock 标题使用的 Unity Localization Entry Key留空时视觉层使用 Block ID 作为开发阶段回退。")]
public string titleKey;
[LabelText("Title")]
[Tooltip("该 TextBlock 的 Unity Localization String Reference。请在此直接选择 String Table 与 Entry留空时视觉层使用 Block ID 作为开发阶段回退。")]
public LocalizedString title = new LocalizedString();
/// <summary>
/// TextBlock 的视觉和叙事层级。Important 用于主线转折与后续 checkpoint
@@ -229,7 +230,9 @@ namespace Ichni.Story
{
string title = blockType switch
{
StoryBlockType.Text => titleKey,
StoryBlockType.Text => this.title != null && !this.title.IsEmpty
? this.title.TableEntryReference.ToString()
: null,
StoryBlockType.Song => songName,
StoryBlockType.Tutorial => tutorialName,
_ => null

View File

@@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEditor.Localization;
using UnityEngine;
using UnityEngine.Localization;
namespace Ichni.Story
{
@@ -146,10 +148,7 @@ namespace Ichni.Story
issues.Add($"[Error] Timeline Marker '{marker.markerId}' 的 Anchor Block '{marker.anchorBlockId}' 不是 TextBlock。");
}
if (string.IsNullOrWhiteSpace(marker.labelKey))
{
issues.Add($"[Warning] Timeline Marker '{marker.markerId}' 未配置 Label Key。");
}
ValidateLocalizedString(marker.label, $"Timeline Marker '{marker.markerId}' Label", issues);
}
ValidateTimelineMarkerAnchors(reachableBlockIds, issues);
@@ -203,8 +202,10 @@ namespace Ichni.Story
switch (block.blockType)
{
case StoryBlockType.Text when string.IsNullOrWhiteSpace(block.yarnNodeName):
issues.Add($"[Warning] TextBlock '{block.blockId}' 未配置 Yarn Node。");
case StoryBlockType.Text:
if (string.IsNullOrWhiteSpace(block.yarnNodeName))
issues.Add($"[Warning] TextBlock '{block.blockId}' 未配置 Yarn Node。");
ValidateLocalizedString(block.title, $"TextBlock '{block.blockId}' Title", issues);
break;
case StoryBlockType.Song when string.IsNullOrWhiteSpace(block.songName):
issues.Add($"[Warning] SongBlock '{block.blockId}' 未配置 Song ID。");
@@ -295,6 +296,36 @@ namespace Ichni.Story
}
}
/// <summary>
/// 检查 LocalizedString 是否已选择有效的 String Table 与 Entry。
/// 只读取 Unity Localization 的 Shared Table Data不加载 Addressables也不修改资产
/// 因此可在 StoryData Inspector 中尽早发现 CSV 尚未导入或引用错误。
/// </summary>
private static void ValidateLocalizedString(
LocalizedString reference,
string owner,
List<string> issues)
{
if (reference == null || reference.IsEmpty)
{
issues.Add($"[Warning] {owner} 未配置 LocalizedString。");
return;
}
StringTableCollection tableCollection =
LocalizationEditorSettings.GetStringTableCollection(reference.TableReference);
if (tableCollection?.SharedData == null)
{
issues.Add($"[Error] {owner} 引用的 String Table '{reference.TableReference}' 不存在或无法读取 Shared Table Data。");
return;
}
if (tableCollection.SharedData.GetEntryFromReference(reference.TableEntryReference) == null)
{
issues.Add($"[Error] {owner} 引用的 Entry '{reference.TableEntryReference}' 不存在于 String Table '{tableCollection.TableCollectionName}'。");
}
}
private HashSet<string> ValidateStoryGraph(HashSet<string> blockIds, List<string> issues)
{
Dictionary<string, List<string>> adjacency = new Dictionary<string, List<string>>();

View File

@@ -1,6 +1,7 @@
using System;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Localization;
namespace Ichni.Story
{
@@ -8,8 +9,8 @@ namespace Ichni.Story
/// 一个章节 Timeline 标记的静态定义。
/// <para>它不保存独立的横坐标:运行时始终跟随锚定 Block 的 <c>gridColumn</c>
/// 使时间轴与剧情树在横向拖动时保持对齐。</para>
/// <para>显示文本和 ID 使用 Unity Localization 的 Entry Key本阶段不绑定具体 String Table
/// 以便后续统一迁移本地化系统时集中配置。</para>
/// <para>显示文本直接使用 <see cref="LocalizedString"/>,因此可在 Inspector 中选择
/// String Table 与 Entry并预览各语言的值。</para>
/// </summary>
[Serializable]
[InlineProperty]
@@ -37,13 +38,13 @@ namespace Ichni.Story
public string anchorBlockId;
/// <summary>
/// Timeline 上显示的本地化文本 Key。通常用于时间描述,也可用于特殊叙事文本。
/// Timeline 上显示的本地化文本。通常用于时间描述,也可用于特殊叙事文本。
/// </summary>
[HorizontalGroup("Identity")]
[LabelText("Label Key")]
[LabelWidth(54)]
[Tooltip("Timeline 上显示的 Unity Localization Entry Key通常用于时间或特殊叙事文本。")]
public string labelKey;
[LabelText("Label")]
[LabelWidth(40)]
[Tooltip("Timeline 上显示的 Unity Localization String Reference。请在此直接选择对应 String Table 与 Entry。")]
public LocalizedString label = new LocalizedString();
/// <summary>
/// 是否参与章节主线进度百分比计算。支线或纯装饰性时间标记应关闭此项。