feat(dialog): 升级Dialog系统到YarnSpinner 3.2
This commit is contained in:
@@ -2762,9 +2762,13 @@ MonoBehaviour:
|
||||
m_GameObject: {fileID: 331068878}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8d3a78e02d644e96a9e0caa46f1e442b, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: a1b2c3d4e5f678901234567890123456, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_textLocaleCode: zh-Hans
|
||||
_assetLocaleCode: zh-Hans
|
||||
_useFallback: 1
|
||||
_fallbackLocaleCode: zh-Hans
|
||||
--- !u!1 &343980037
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -12746,15 +12750,17 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
yarnProject: {fileID: 0}
|
||||
_variableStorage: {fileID: 314243163}
|
||||
dialogueViews:
|
||||
variableStorage: {fileID: 314243163}
|
||||
lineProvider: {fileID: 331068880}
|
||||
saliencyStrategy: 0
|
||||
dialoguePresenters:
|
||||
- {fileID: 1829169897}
|
||||
- {fileID: 381795663}
|
||||
startNode: Start
|
||||
startAutomatically: 0
|
||||
runSelectedOptionAsLine: 0
|
||||
lineProvider: {fileID: 331068880}
|
||||
verboseLogging: 1
|
||||
autoStart: 0
|
||||
startNode: Start
|
||||
runSelectedOptionAsLine: 0
|
||||
allowOptionFallthrough: 1
|
||||
onNodeStart:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
@@ -12767,7 +12773,7 @@ MonoBehaviour:
|
||||
onDialogueComplete:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
onCommand:
|
||||
onUnhandledCommand:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &1937938009
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1b2c3d4e5f678901234567890123456
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -2,21 +2,23 @@
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Kit;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class DialogController : Singleton<DialogController>
|
||||
{
|
||||
private const string DefaultDialogueLocaleCode = "zh-Hans";
|
||||
private DialogueRunner _dialogueRunner;
|
||||
private LocalisedLineProvider _lineProvider;
|
||||
|
||||
[SerializeField] private LineAdvanceInput lineAdvanceInput;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_dialogueRunner = GetComponentInChildren<DialogueRunner>();
|
||||
_lineProvider = GetComponentInChildren<LocalisedLineProvider>();
|
||||
_dialogueRunner.onDialogueStart ??= new UnityEvent();
|
||||
_dialogueRunner.onDialogueComplete ??= new UnityEvent();
|
||||
|
||||
_dialogueRunner.onDialogueStart.AddListener(() =>
|
||||
{
|
||||
@@ -72,13 +74,13 @@ namespace AibisDream
|
||||
public void StartDialog(YarnProject yarnProject)
|
||||
{
|
||||
_dialogueRunner.SetProject(yarnProject);
|
||||
_lineProvider.InitStringTable(yarnProject.name);
|
||||
_dialogueRunner.StartDialogue("Start");
|
||||
ConfigureLineProviderLocale();
|
||||
_ = _dialogueRunner.StartDialogue("Start");
|
||||
}
|
||||
|
||||
public void StopDialog()
|
||||
{
|
||||
_dialogueRunner.Stop();
|
||||
_ = _dialogueRunner.Stop();
|
||||
StorageSystem.Instance.Clear();
|
||||
DialogUIManager.Instance.HideDialog();
|
||||
}
|
||||
@@ -86,8 +88,8 @@ namespace AibisDream
|
||||
public void LoadDialog(YarnProject yarnProject)
|
||||
{
|
||||
_dialogueRunner.SetProject(yarnProject);
|
||||
_lineProvider.InitStringTable(yarnProject.name);
|
||||
_dialogueRunner.StartDialogue("Center");
|
||||
ConfigureLineProviderLocale();
|
||||
_ = _dialogueRunner.StartDialogue("Center");
|
||||
}
|
||||
|
||||
public void StartDialogNode(string nodeName)
|
||||
@@ -101,7 +103,7 @@ namespace AibisDream
|
||||
|
||||
if (CheckIfNodeExistInCurrentYarnProject(nodeName))
|
||||
{
|
||||
_dialogueRunner.StartDialogue(nodeName);
|
||||
_ = _dialogueRunner.StartDialogue(nodeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,7 +113,13 @@ namespace AibisDream
|
||||
|
||||
private bool CheckIfNodeExistInCurrentYarnProject(string nodeName)
|
||||
{
|
||||
YarnProject currentProject = _dialogueRunner.yarnProject;
|
||||
var currentProject = _dialogueRunner.YarnProject;
|
||||
if (currentProject == null)
|
||||
{
|
||||
Debug.LogWarning("当前没有可用的 YarnProject,无法检查节点");
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] nodeNames = currentProject.NodeNames;
|
||||
if (Array.Exists(nodeNames, item => item == nodeName))
|
||||
{
|
||||
@@ -124,6 +132,14 @@ namespace AibisDream
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureLineProviderLocale()
|
||||
{
|
||||
if (_dialogueRunner.LineProvider is LineProviderBehaviour lineProvider)
|
||||
{
|
||||
lineProvider.LocaleCode = DefaultDialogueLocaleCode;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 推进方式修改
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Utility;
|
||||
using UnityEngine;
|
||||
@@ -6,22 +5,79 @@ using Yarn.Unity;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class LineRunner : DialogueViewBase
|
||||
public class LineRunner : DialoguePresenterBase
|
||||
{
|
||||
[SerializeField] private LineAdvanceInput advanceInput;
|
||||
[SerializeField] private DialogViewType defaultViewType = DialogViewType.StandardBubble;
|
||||
|
||||
private readonly Dictionary<DialogViewType, ILineView> _screenViewDict = new();
|
||||
|
||||
public override void RunLine(LocalizedLine dialogueLine, Action onDialogueLineFinished)
|
||||
public override YarnTask OnDialogueStartedAsync()
|
||||
{
|
||||
LineSyncToken lineSyncEvent;
|
||||
return YarnTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override YarnTask OnDialogueCompleteAsync()
|
||||
{
|
||||
HideDialog();
|
||||
return YarnTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override async YarnTask RunLineAsync(LocalizedLine dialogueLine, LineCancellationToken token)
|
||||
{
|
||||
var lineSyncEvent = BuildSyncToken(dialogueLine);
|
||||
DialogController.Instance.lineSyncToken = lineSyncEvent;
|
||||
DispatchToView(dialogueLine, lineSyncEvent);
|
||||
|
||||
// 最后交给推进处理
|
||||
advanceInput.RunLine(lineSyncEvent);
|
||||
|
||||
using var skipReg = token.HurryUpToken.Register(() =>
|
||||
{
|
||||
if (lineSyncEvent.state == LineSyncState.PlayText)
|
||||
{
|
||||
lineSyncEvent.TrySkip();
|
||||
}
|
||||
});
|
||||
|
||||
using var advanceReg = token.NextContentToken.Register(() =>
|
||||
{
|
||||
if (lineSyncEvent.state != LineSyncState.Advanced)
|
||||
{
|
||||
lineSyncEvent.ForceAdvance();
|
||||
}
|
||||
});
|
||||
|
||||
await lineSyncEvent.AwaitCompletion();
|
||||
}
|
||||
|
||||
private LineSyncToken BuildSyncToken(LocalizedLine dialogueLine)
|
||||
{
|
||||
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Screen)
|
||||
{
|
||||
// 自动推进视图
|
||||
lineSyncEvent = LineSyncToken.CreateAuto(dialogueLine, onDialogueLineFinished);
|
||||
DialogController.Instance.lineSyncToken = lineSyncEvent;
|
||||
return LineSyncToken.CreateAuto(dialogueLine);
|
||||
}
|
||||
|
||||
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Task)
|
||||
{
|
||||
return LineSyncToken.CreateImmediate(dialogueLine);
|
||||
}
|
||||
|
||||
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Default)
|
||||
{
|
||||
// 手动推进视图
|
||||
return LineSyncToken.CreateDefault(dialogueLine);
|
||||
}
|
||||
|
||||
// 指定了视图类型
|
||||
return LineSyncToken.CreateDefault(dialogueLine);
|
||||
}
|
||||
|
||||
private void DispatchToView(LocalizedLine dialogueLine, LineSyncToken lineSyncEvent)
|
||||
{
|
||||
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Screen)
|
||||
{
|
||||
if (_screenViewDict.TryGetValue(DialogViewType.Screen, out var view))
|
||||
{
|
||||
view.RunLine(lineSyncEvent);
|
||||
@@ -30,11 +86,11 @@ namespace AibisDream
|
||||
{
|
||||
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Task)
|
||||
|
||||
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Task)
|
||||
{
|
||||
lineSyncEvent = LineSyncToken.CreateImmediate(dialogueLine, onDialogueLineFinished);
|
||||
DialogController.Instance.lineSyncToken = lineSyncEvent;
|
||||
if (_screenViewDict.TryGetValue(DialogViewType.Task, out var view))
|
||||
{
|
||||
view.RunLine(lineSyncEvent);
|
||||
@@ -43,39 +99,30 @@ namespace AibisDream
|
||||
{
|
||||
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Default)
|
||||
{
|
||||
// 手动推进视图
|
||||
lineSyncEvent = LineSyncToken.CreateDefault(dialogueLine, onDialogueLineFinished);
|
||||
|
||||
if (dialogueLine.GetCharacterVo().dialogViewType == DialogViewType.Default)
|
||||
{
|
||||
if (_screenViewDict.TryGetValue(defaultViewType, out var view))
|
||||
{
|
||||
DialogController.Instance.lineSyncToken = lineSyncEvent;
|
||||
view.RunLine(lineSyncEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"未注册的视图类型: {defaultViewType}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_screenViewDict.TryGetValue(dialogueLine.GetCharacterVo().dialogViewType, out var specificView))
|
||||
{
|
||||
specificView.RunLine(lineSyncEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 指定了视图类型
|
||||
lineSyncEvent = LineSyncToken.CreateDefault(dialogueLine, onDialogueLineFinished);
|
||||
if (_screenViewDict.TryGetValue(dialogueLine.GetCharacterVo().dialogViewType, out var view))
|
||||
{
|
||||
DialogController.Instance.lineSyncToken = lineSyncEvent;
|
||||
view.RunLine(lineSyncEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
|
||||
}
|
||||
Debug.LogWarning($"未注册的视图类型: {dialogueLine.GetCharacterVo().dialogViewType}");
|
||||
}
|
||||
|
||||
// 最后交给推进处理
|
||||
advanceInput.RunLine(lineSyncEvent);
|
||||
}
|
||||
|
||||
public void LoadBubbleData(BubbleSlotGroupData data)
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace AibisDream
|
||||
{
|
||||
private Action _nextStep;
|
||||
private readonly ITextShown _textShown;
|
||||
private readonly TaskCompletionSource<bool> _completion = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
public LineInfo lineInfo;
|
||||
public LineSyncState state;
|
||||
@@ -27,11 +28,21 @@ namespace AibisDream
|
||||
return new LineSyncToken(lineInfo, nextStep, new AutoNextTextShown());
|
||||
}
|
||||
|
||||
public static LineSyncToken CreateAuto(LocalizedLine lineInfo)
|
||||
{
|
||||
return new LineSyncToken(lineInfo, null, new AutoNextTextShown());
|
||||
}
|
||||
|
||||
public static LineSyncToken CreateImmediate(LocalizedLine lineInfo, Action nextStep)
|
||||
{
|
||||
return new LineSyncToken(lineInfo, nextStep, new ImmediateTextShown());
|
||||
}
|
||||
|
||||
public static LineSyncToken CreateImmediate(LocalizedLine lineInfo)
|
||||
{
|
||||
return new LineSyncToken(lineInfo, null, new ImmediateTextShown());
|
||||
}
|
||||
|
||||
public static LineSyncToken CreateDefault(LocalizedLine lineInfo, Action nextStep)
|
||||
{
|
||||
// 如果标记了 auto_next,使用自动推进逻辑
|
||||
@@ -42,6 +53,16 @@ namespace AibisDream
|
||||
return new LineSyncToken(lineInfo, nextStep, new DefaultTextShown());
|
||||
}
|
||||
|
||||
public static LineSyncToken CreateDefault(LocalizedLine lineInfo)
|
||||
{
|
||||
// 如果标记了 auto_next,使用自动推进逻辑
|
||||
if (lineInfo.IsAutoSkipLine())
|
||||
{
|
||||
return new LineSyncToken(lineInfo, null, new AutoNextTextShown());
|
||||
}
|
||||
return new LineSyncToken(lineInfo, null, new DefaultTextShown());
|
||||
}
|
||||
|
||||
public LineSyncToken(LocalizedLine lineInfo, Action nextStep, ITextShown textShown)
|
||||
{
|
||||
this.lineInfo = LineInfo.Generate(lineInfo);
|
||||
@@ -96,6 +117,7 @@ namespace AibisDream
|
||||
OnAdvance = null;
|
||||
_nextStep?.Invoke();
|
||||
state = LineSyncState.Advanced;
|
||||
_completion.TrySetResult(true);
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
@@ -121,6 +143,11 @@ namespace AibisDream
|
||||
state = LineSyncState.PlayText;
|
||||
EnumEventSystem.Global.Send(DialogEventEnum.LineStart, lineInfo);
|
||||
}
|
||||
|
||||
public Task AwaitCompletion()
|
||||
{
|
||||
return _completion.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public struct LineInfo
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
using System.Linq;
|
||||
using UnityEngine.Localization.Settings;
|
||||
using Yarn.Unity;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Utility;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class LocalisedLineProvider : LineProviderBehaviour
|
||||
{
|
||||
private LocalizationTable _localizationTable;
|
||||
|
||||
public override string LocaleCode => LocalizationSettings.SelectedLocale.Identifier.Code;
|
||||
|
||||
// 本地化表存在即可用
|
||||
public override bool LinesAvailable => _localizationTable != null;
|
||||
|
||||
public override LocalizedLine GetLocalizedLine(Yarn.Line line)
|
||||
{
|
||||
var text = line.ID;
|
||||
if (_localizationTable != null)
|
||||
{
|
||||
text = _localizationTable[line.ID]?.LocalizedValue ??
|
||||
$"Error: Missing localisation for line {line.ID} in string table {_localizationTable.LocaleIdentifier}";
|
||||
}
|
||||
|
||||
LocalizeSubstitutions(line);
|
||||
var resText = CommonUtil.Escape(text);
|
||||
|
||||
// Construct the localized line
|
||||
LocalizedLine localizedLine = new LocalizedLine
|
||||
{
|
||||
TextID = line.ID,
|
||||
RawText = resText,
|
||||
Substitutions = line.Substitutions,
|
||||
Metadata = YarnProject.lineMetadata.GetMetadata(line.ID)
|
||||
};
|
||||
|
||||
// Attempt to fetch metadata tags for this line from the string
|
||||
// table
|
||||
if (_localizationTable == null) return localizedLine;
|
||||
|
||||
var metadata = _localizationTable[line.ID]?.SharedEntry.Metadata
|
||||
.GetMetadata<Yarn.Unity.UnityLocalization.LineMetadata>();
|
||||
|
||||
if (metadata != null && localizedLine.Metadata != null)
|
||||
{
|
||||
localizedLine.Metadata = localizedLine.Metadata.Concat(metadata.tags).ToArray();
|
||||
}
|
||||
else if (localizedLine.Metadata == null && metadata != null)
|
||||
{
|
||||
localizedLine.Metadata = metadata.tags;
|
||||
}
|
||||
|
||||
return localizedLine;
|
||||
}
|
||||
|
||||
private void LocalizeSubstitutions(Yarn.Line line)
|
||||
{
|
||||
for (var i = 0; i < line.Substitutions.Length; i++)
|
||||
{
|
||||
line.Substitutions[i] = LocalizationKit.LocalizeParam(line.Substitutions[i], _localizationTable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化StringTable
|
||||
/// </summary>
|
||||
/// <param name="tableName">本地化表名称</param>
|
||||
/// <returns>协程</returns>
|
||||
public void InitStringTable(string tableName)
|
||||
{
|
||||
// 释放
|
||||
_localizationTable?.Dispose();
|
||||
// 加载
|
||||
_localizationTable = new LocalizationTable(tableName);
|
||||
}
|
||||
|
||||
public string GetStringTableName()
|
||||
{
|
||||
return _localizationTable.TableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d3a78e02d644e96a9e0caa46f1e442b
|
||||
timeCreated: 1745489761
|
||||
@@ -1,12 +1,14 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using AibisDream.Framework;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class OptionView : DialogueViewBase
|
||||
public class OptionView : DialoguePresenterBase
|
||||
{
|
||||
private HashSet<string> _selectedIds = new();
|
||||
[SerializeField] private DefaultOptions defaultOptions;
|
||||
@@ -14,15 +16,35 @@ namespace AibisDream
|
||||
[SerializeField] private OnelineOptions onelineOptions;
|
||||
[SerializeField] private DialogViewType defaultViewType = DialogViewType.StandardBubble;
|
||||
|
||||
public override YarnTask OnDialogueStartedAsync()
|
||||
{
|
||||
return YarnTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override YarnTask OnDialogueCompleteAsync()
|
||||
{
|
||||
HideDialog();
|
||||
return YarnTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override YarnTask RunLineAsync(LocalizedLine line, LineCancellationToken token)
|
||||
{
|
||||
return YarnTask.CompletedTask;
|
||||
}
|
||||
|
||||
public void LoadBubbles(BubbleSlotGroupData data)
|
||||
{
|
||||
defaultViewType = data.dialogViewType;
|
||||
}
|
||||
|
||||
public override void RunOptions(DialogueOption[] dialogueOptions, Action<int> onOptionSelected)
|
||||
public override async YarnTask<DialogueOption?> RunOptionsAsync(DialogueOption[] dialogueOptions, LineCancellationToken cancellationToken)
|
||||
{
|
||||
EnumEventSystem.Global.Send(DialogEventEnum.OptionShow);
|
||||
var options = DialogOption.GeneOptions(dialogueOptions, onOptionSelected, _selectedIds);
|
||||
var optionSelectedSource = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var options = DialogOption.GeneOptions(dialogueOptions, optionId =>
|
||||
{
|
||||
optionSelectedSource.TrySetResult(optionId);
|
||||
}, _selectedIds);
|
||||
|
||||
var viewType = GetCurrentViewType(options);
|
||||
|
||||
@@ -42,6 +64,29 @@ namespace AibisDream
|
||||
Debug.Log($"选项{options[0].Character.key}没有找到选项框{viewType}");
|
||||
break;
|
||||
}
|
||||
|
||||
using var cancellationReg = cancellationToken.NextContentToken.Register(() =>
|
||||
{
|
||||
optionSelectedSource.TrySetCanceled(cancellationToken.NextContentToken);
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
var selectedOptionId = await optionSelectedSource.Task;
|
||||
foreach (var dialogueOption in dialogueOptions)
|
||||
{
|
||||
if (dialogueOption.DialogueOptionID == selectedOptionId)
|
||||
{
|
||||
return dialogueOption;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private DialogViewType GetCurrentViewType(DialogOption[] options)
|
||||
|
||||
Reference in New Issue
Block a user