Files
aibis-dream/Assets/Scripts/Dialog System/AibisLineProvider.cs
T

193 lines
6.4 KiB
C#

using System.Collections.Generic;
using System.Threading;
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;
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 的能力)
for (int i = 0; i < line.Substitutions.Length; i++)
{
line.Substitutions[i] = LocalizationKit.LocalizeParam(line.Substitutions[i]);
}
// 保留旧 LocalisedLineProvider 的文本转义处理
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);
}
}
}