From b447d4784c216f84df50655c7c97ccb68d0c9686 Mon Sep 17 00:00:00 2001 From: Ding Yuntian <1491671119@qq.com> Date: Thu, 23 Apr 2026 11:55:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(dialog):=20=E5=8D=87=E7=BA=A7Dialog?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=88=B0YarnSpinner=203.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scenes/Persistence.unity | 22 +- .../Dialog System/AibisLineProvider.cs | 188 ++++++++++++++++++ .../Dialog System/AibisLineProvider.cs.meta | 11 + .../Scripts/Dialog System/DialogController.cs | 34 +++- Assets/Scripts/Dialog System/LineRunner.cs | 103 +++++++--- Assets/Scripts/Dialog System/LineSyncToken.cs | 27 +++ .../Dialog System/LocalisedLineProvider.cs | 84 -------- .../LocalisedLineProvider.cs.meta | 3 - Assets/Scripts/Dialog System/OptionView.cs | 53 ++++- 9 files changed, 389 insertions(+), 136 deletions(-) create mode 100644 Assets/Scripts/Dialog System/AibisLineProvider.cs create mode 100644 Assets/Scripts/Dialog System/AibisLineProvider.cs.meta delete mode 100644 Assets/Scripts/Dialog System/LocalisedLineProvider.cs delete mode 100644 Assets/Scripts/Dialog System/LocalisedLineProvider.cs.meta diff --git a/Assets/Scenes/Persistence.unity b/Assets/Scenes/Persistence.unity index be75542b4..ae192c2ef 100644 --- a/Assets/Scenes/Persistence.unity +++ b/Assets/Scenes/Persistence.unity @@ -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 diff --git a/Assets/Scripts/Dialog System/AibisLineProvider.cs b/Assets/Scripts/Dialog System/AibisLineProvider.cs new file mode 100644 index 000000000..8bf066ff4 --- /dev/null +++ b/Assets/Scripts/Dialog System/AibisLineProvider.cs @@ -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 GetLocalizedLineAsync(Yarn.Line line, CancellationToken cancellationToken) + { + string sourceLineID = line.ID; + + string[] metadata = System.Array.Empty(); + + if (YarnProject != null) + { + metadata = YarnProject.lineMetadata?.GetMetadata(line.ID) ?? System.Array.Empty(); + + 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 GetLocalizedAssetAsync(string sourceLineID) + { + var baseLoc = GetLocalization(_assetLocaleCode); + Object result = await baseLoc.GetLocalizedObjectAsync(sourceLineID); + + if (result != null) + { + return result; + } + + if (_useFallback) + { + var fallbackLoc = GetLocalization(_fallbackLocaleCode); + return await fallbackLoc.GetLocalizedObjectAsync(sourceLineID); + } + + return null; + } + + public async override YarnTask PrepareForLinesAsync(IEnumerable lineIDs, CancellationToken cancellationToken) + { + if (YarnProject == null) + { + return; + } + + var assetLocalization = YarnProject.GetLocalization(AssetLocaleCode); + + if (assetLocalization.UsesAddressableAssets) + { + var tasks = new List>(); + + foreach (var id in lineIDs) + { + var task = assetLocalization.GetLocalizedObjectAsync(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); + } + } +} diff --git a/Assets/Scripts/Dialog System/AibisLineProvider.cs.meta b/Assets/Scripts/Dialog System/AibisLineProvider.cs.meta new file mode 100644 index 000000000..59403d0f8 --- /dev/null +++ b/Assets/Scripts/Dialog System/AibisLineProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a1b2c3d4e5f678901234567890123456 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Dialog System/DialogController.cs b/Assets/Scripts/Dialog System/DialogController.cs index dcd4af54f..027a3d2b8 100644 --- a/Assets/Scripts/Dialog System/DialogController.cs +++ b/Assets/Scripts/Dialog System/DialogController.cs @@ -2,21 +2,23 @@ using AibisDream.Framework; using AibisDream.Kit; using UnityEngine; +using UnityEngine.Events; using Yarn.Unity; namespace AibisDream { public class DialogController : Singleton { + private const string DefaultDialogueLocaleCode = "zh-Hans"; private DialogueRunner _dialogueRunner; - private LocalisedLineProvider _lineProvider; [SerializeField] private LineAdvanceInput lineAdvanceInput; private void Start() { _dialogueRunner = GetComponentInChildren(); - _lineProvider = GetComponentInChildren(); + _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 推进方式修改 diff --git a/Assets/Scripts/Dialog System/LineRunner.cs b/Assets/Scripts/Dialog System/LineRunner.cs index 0adf9c20c..f09026df7 100644 --- a/Assets/Scripts/Dialog System/LineRunner.cs +++ b/Assets/Scripts/Dialog System/LineRunner.cs @@ -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 _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) diff --git a/Assets/Scripts/Dialog System/LineSyncToken.cs b/Assets/Scripts/Dialog System/LineSyncToken.cs index a471c8062..ae42b0523 100644 --- a/Assets/Scripts/Dialog System/LineSyncToken.cs +++ b/Assets/Scripts/Dialog System/LineSyncToken.cs @@ -14,6 +14,7 @@ namespace AibisDream { private Action _nextStep; private readonly ITextShown _textShown; + private readonly TaskCompletionSource _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 diff --git a/Assets/Scripts/Dialog System/LocalisedLineProvider.cs b/Assets/Scripts/Dialog System/LocalisedLineProvider.cs deleted file mode 100644 index c7cd6c8b2..000000000 --- a/Assets/Scripts/Dialog System/LocalisedLineProvider.cs +++ /dev/null @@ -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(); - - 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); - } - } - - /// - /// 初始化StringTable - /// - /// 本地化表名称 - /// 协程 - public void InitStringTable(string tableName) - { - // 释放 - _localizationTable?.Dispose(); - // 加载 - _localizationTable = new LocalizationTable(tableName); - } - - public string GetStringTableName() - { - return _localizationTable.TableName; - } - } -} \ No newline at end of file diff --git a/Assets/Scripts/Dialog System/LocalisedLineProvider.cs.meta b/Assets/Scripts/Dialog System/LocalisedLineProvider.cs.meta deleted file mode 100644 index 02d68fbb5..000000000 --- a/Assets/Scripts/Dialog System/LocalisedLineProvider.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 8d3a78e02d644e96a9e0caa46f1e442b -timeCreated: 1745489761 \ No newline at end of file diff --git a/Assets/Scripts/Dialog System/OptionView.cs b/Assets/Scripts/Dialog System/OptionView.cs index 6b389ea55..def71eb3f 100644 --- a/Assets/Scripts/Dialog System/OptionView.cs +++ b/Assets/Scripts/Dialog System/OptionView.cs @@ -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 _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 onOptionSelected) + public override async YarnTask RunOptionsAsync(DialogueOption[] dialogueOptions, LineCancellationToken cancellationToken) { EnumEventSystem.Global.Send(DialogEventEnum.OptionShow); - var options = DialogOption.GeneOptions(dialogueOptions, onOptionSelected, _selectedIds); + var optionSelectedSource = new TaskCompletionSource(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)