205 lines
7.1 KiB
C#
205 lines
7.1 KiB
C#
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using AibisDream.Framework;
|
|
using AibisDream.Utility;
|
|
using UnityEngine;
|
|
using Yarn.Unity;
|
|
using Yarn.Unity.Attributes;
|
|
|
|
namespace AibisDream
|
|
{
|
|
public class AibisLineProvider : LineProviderBehaviour
|
|
{
|
|
public override string LocaleCode
|
|
{
|
|
get => _textLocaleCode;
|
|
set => _textLocaleCode = value;
|
|
}
|
|
|
|
[SerializeField, Language]
|
|
private string _textLocaleCode = System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
|
|
|
|
[SerializeField, Language]
|
|
private string _assetLocaleCode = System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
|
|
|
|
[SerializeField]
|
|
private bool _useFallback = false;
|
|
|
|
[ShowIf(nameof(_useFallback))]
|
|
[SerializeField, Language]
|
|
private string _fallbackLocaleCode = System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
|
|
|
|
[SerializeField]
|
|
private NarrativeTextStyleConfig _narrativeTextStyle;
|
|
|
|
public string AssetLocaleCode
|
|
{
|
|
get => _assetLocaleCode;
|
|
set => _assetLocaleCode = value;
|
|
}
|
|
|
|
private Yarn.Markup.LineParser lineParser = new Yarn.Markup.LineParser();
|
|
private Yarn.Markup.BuiltInMarkupReplacer builtInReplacer = new Yarn.Markup.BuiltInMarkupReplacer();
|
|
|
|
void Awake()
|
|
{
|
|
lineParser.RegisterMarkerProcessor("select", builtInReplacer);
|
|
lineParser.RegisterMarkerProcessor("plural", builtInReplacer);
|
|
lineParser.RegisterMarkerProcessor("ordinal", builtInReplacer);
|
|
}
|
|
|
|
public override async YarnTask<LocalizedLine> GetLocalizedLineAsync(Yarn.Line line, CancellationToken cancellationToken)
|
|
{
|
|
// 每行对白即是消费点:在此同步一次当前语言,保证对话进行中切语言下一行立即生效
|
|
_textLocaleCode = LocalizationKit.CurrentLanguageCode;
|
|
_assetLocaleCode = LocalizationKit.CurrentLanguageCode;
|
|
|
|
string sourceLineID = line.ID;
|
|
|
|
string[] metadata = System.Array.Empty<string>();
|
|
|
|
if (YarnProject != null)
|
|
{
|
|
metadata = YarnProject.lineMetadata?.GetMetadata(line.ID) ?? System.Array.Empty<string>();
|
|
|
|
var shadowLineSource = YarnProject.lineMetadata?.GetShadowLineSource(line.ID);
|
|
|
|
if (shadowLineSource != null)
|
|
{
|
|
sourceLineID = shadowLineSource;
|
|
}
|
|
}
|
|
|
|
string text = GetLocalizedString(sourceLineID);
|
|
Object asset = await GetLocalizedAssetAsync(sourceLineID);
|
|
|
|
if (text == null)
|
|
{
|
|
Debug.LogWarning($"Localization {LocaleCode} does not contain an entry for line {line.ID}", this);
|
|
return LocalizedLine.InvalidLine;
|
|
}
|
|
|
|
// 对 substitutions 并行做本地化解析(保留旧 LocalisedLineProvider 的能力)。
|
|
if (line.Substitutions.Length > 0)
|
|
{
|
|
var localizationTasks = new Task<string>[line.Substitutions.Length];
|
|
for (int i = 0; i < line.Substitutions.Length; i++)
|
|
localizationTasks[i] = LocalizationKit.LocalizeParamAsync(line.Substitutions[i]);
|
|
|
|
string[] localizedSubstitutions = await Task.WhenAll(localizationTasks);
|
|
for (int i = 0; i < localizedSubstitutions.Length; i++)
|
|
line.Substitutions[i] = localizedSubstitutions[i];
|
|
}
|
|
|
|
// 先展开项目级语义标记,再保留旧 LocalisedLineProvider 的文本转义处理。
|
|
// ULM 的 [[vertexp ...]] 会由 Escape 转成 Text Animator 使用的花括号标签。
|
|
text = NarrativeTextStyleExpander.Expand(text, _narrativeTextStyle);
|
|
text = CommonUtil.Escape(text);
|
|
|
|
var parseResult = lineParser.ParseString(Yarn.Markup.LineParser.ExpandSubstitutions(text, line.Substitutions), LocaleCode);
|
|
|
|
return new LocalizedLine
|
|
{
|
|
Text = parseResult,
|
|
RawText = text,
|
|
TextID = line.ID,
|
|
Asset = asset,
|
|
Metadata = metadata,
|
|
};
|
|
}
|
|
|
|
private Yarn.Unity.Localization GetLocalization(string locale)
|
|
{
|
|
if (YarnProject == null)
|
|
{
|
|
throw new System.InvalidOperationException("Can't get localized line: no Yarn Project set");
|
|
}
|
|
|
|
Localization loc = YarnProject.GetLocalization(locale);
|
|
|
|
if (loc == null)
|
|
{
|
|
throw new System.InvalidOperationException($"Can't get localized line: Yarn Project has no localisation for {locale}");
|
|
}
|
|
|
|
return loc;
|
|
}
|
|
|
|
private string GetLocalizedString(string sourceLineID)
|
|
{
|
|
var baseLoc = GetLocalization(_textLocaleCode);
|
|
string localizedText = baseLoc.GetLocalizedString(sourceLineID);
|
|
|
|
if (localizedText != null)
|
|
{
|
|
return localizedText;
|
|
}
|
|
|
|
if (_useFallback)
|
|
{
|
|
var fallbackLoc = GetLocalization(_fallbackLocaleCode);
|
|
return fallbackLoc.GetLocalizedString(sourceLineID);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async YarnTask<Object> GetLocalizedAssetAsync(string sourceLineID)
|
|
{
|
|
var baseLoc = GetLocalization(_assetLocaleCode);
|
|
Object result = await baseLoc.GetLocalizedObjectAsync<Object>(sourceLineID);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (_useFallback)
|
|
{
|
|
var fallbackLoc = GetLocalization(_fallbackLocaleCode);
|
|
return await fallbackLoc.GetLocalizedObjectAsync<Object>(sourceLineID);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async override YarnTask PrepareForLinesAsync(IEnumerable<string> lineIDs, CancellationToken cancellationToken)
|
|
{
|
|
if (YarnProject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var assetLocalization = YarnProject.GetLocalization(AssetLocaleCode);
|
|
|
|
if (assetLocalization.UsesAddressableAssets)
|
|
{
|
|
var tasks = new List<YarnTask<Object>>();
|
|
|
|
foreach (var id in lineIDs)
|
|
{
|
|
var task = assetLocalization.GetLocalizedObjectAsync<Object>(id);
|
|
tasks.Add(task);
|
|
}
|
|
|
|
await YarnTask.WhenAll(tasks);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
public override void RegisterMarkerProcessor(string attributeName, Yarn.Markup.IAttributeMarkerProcessor markerProcessor)
|
|
{
|
|
lineParser.RegisterMarkerProcessor(attributeName, markerProcessor);
|
|
}
|
|
|
|
public override void DeregisterMarkerProcessor(string attributeName)
|
|
{
|
|
lineParser.DeregisterMarkerProcessor(attributeName);
|
|
}
|
|
}
|
|
}
|