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

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace Ichni.Localization
{
/// <summary>
/// 项目运行时代码读取 Unity Localization 文本的统一入口。
/// <para>静态 Prefab 文本仍应使用 <c>LocalizeStringEvent</c>只有运行时生成、Yarn 命令、Story 数据等无法直接挂组件的文本才调用本服务。</para>
/// <para>同步接口绝不强制 Addressables 完成加载Localization 尚未就绪时直接返回 fallback避免在场景切换或 UI 点击中制造卡顿。</para>
/// </summary>
public static class LocalizationTextService
{
private static readonly HashSet<string> ReportedFallbacks = new HashSet<string>();
/// <summary>
/// 在 Unity Localization 已初始化时立即解析文本;无法解析时返回调用方提供的 fallback。
/// <para>fallback 传入 <c>null</c> 时回退显示 Key适合开发阶段快速定位缺失条目传入空字符串时会保留空字符串。</para>
/// </summary>
public static string Resolve(
TableReference tableReference,
string entryKey,
string fallback = null,
params object[] arguments)
{
string resolvedFallback = GetFallback(entryKey, fallback);
if (string.IsNullOrEmpty(entryKey))
{
return resolvedFallback;
}
AsyncOperationHandle<LocalizationSettings> initializationOperation = LocalizationSettings.InitializationOperation;
if (!initializationOperation.IsDone || initializationOperation.Status != AsyncOperationStatus.Succeeded)
{
ReportFallbackOnce(tableReference, entryKey, "Unity Localization 尚未完成初始化");
return resolvedFallback;
}
try
{
string localizedText = LocalizationSettings.StringDatabase.GetLocalizedString(
tableReference,
entryKey,
null,
FallbackBehavior.UseProjectSettings,
arguments);
if (!string.IsNullOrEmpty(localizedText))
{
return localizedText;
}
ReportFallbackOnce(tableReference, entryKey, "String Table 未返回有效文本");
}
catch (Exception exception)
{
ReportFallbackOnce(tableReference, entryKey, exception.Message);
}
return resolvedFallback;
}
/// <summary>
/// 异步解析文本。该接口只等待 Unity 官方 <see cref="LocalizationSettings.InitializationOperation"/> 和字符串加载操作,
/// 不创建额外 Bootstrap也不使用 <c>WaitForCompletion</c> 阻塞主线程。
/// </summary>
public static async Task<string> ResolveAsync(
TableReference tableReference,
string entryKey,
string fallback = null,
params object[] arguments)
{
string resolvedFallback = GetFallback(entryKey, fallback);
if (string.IsNullOrEmpty(entryKey))
{
return resolvedFallback;
}
try
{
AsyncOperationHandle<LocalizationSettings> initializationOperation = LocalizationSettings.InitializationOperation;
await initializationOperation.Task;
if (initializationOperation.Status != AsyncOperationStatus.Succeeded)
{
ReportFallbackOnce(tableReference, entryKey, "Unity Localization 初始化失败");
return resolvedFallback;
}
AsyncOperationHandle<string> textOperation = LocalizationSettings.StringDatabase.GetLocalizedStringAsync(
tableReference,
entryKey,
null,
FallbackBehavior.UseProjectSettings,
arguments);
await textOperation.Task;
if (textOperation.Status == AsyncOperationStatus.Succeeded && !string.IsNullOrEmpty(textOperation.Result))
{
return textOperation.Result;
}
ReportFallbackOnce(tableReference, entryKey, "String Table 异步加载失败或未返回有效文本");
}
catch (Exception exception)
{
ReportFallbackOnce(tableReference, entryKey, exception.Message);
}
return resolvedFallback;
}
private static string GetFallback(string entryKey, string fallback)
{
return fallback ?? entryKey ?? string.Empty;
}
/// <summary>
/// 同一 Table/Key 的回退原因只输出一次,避免 Helper、Timeline 等重复刷新 UI 时刷屏。
/// </summary>
private static void ReportFallbackOnce(TableReference tableReference, string entryKey, string reason)
{
string diagnosticKey = $"{tableReference}:{entryKey}";
if (!ReportedFallbacks.Add(diagnosticKey))
{
return;
}
Debug.LogWarning($"[LocalizationTextService] 无法解析 '{diagnosticKey}',将显示 fallback。原因{reason}");
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5d611ba2aff044f89da2f79bc04cf75a