using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading; using BITKit; using Cysharp.Threading.Tasks; namespace Net.Project.B.Dialogue { /// /// 对话服务 /// public interface IDialogueService { /// /// 所有对话 /// IReadOnlyDictionary Dialogues { get; } /// /// 对话开始 /// public event Func OnDialogueStart; public event Action OnDynamicDialogueStart; /// /// 动态对话 /// public event Func> OnDynamicDialogueStartAsync; /// /// 对话结束 /// public event Action OnDialogueEnd; /// /// 动态对话结束 /// public event Action OnDynamicDialogueEnd; /// /// 对话选择 /// public event Func, UniTask> OnDialogueChoose; /// /// 对话选择回调 /// public event Action OnDialogueChose; /// /// 开启对话 /// /// 对话 /// UniTask CreateDialogue(IDialogueData dialogueData); UniTask CreateDialogue(IDialogueData dialogueData, IReadOnlyCollection dialogueChoices); UniTask CreateDynamicDialogue(IDialogueData dialogueData); } public class DialogueService : IDialogueService { public IReadOnlyDictionary Dialogues => _dialogues; public event Func OnDialogueStart; public event Action OnDynamicDialogueStart; public event Func> OnDynamicDialogueStartAsync; public event Action OnDialogueEnd; public event Action OnDynamicDialogueEnd; public event Func, UniTask> OnDialogueChoose; public event Action OnDialogueChose; public async UniTask CreateDialogue(IDialogueData dialogueData) { dialogueData.CancellationTokenSource ??= new CancellationTokenSource(); if (_dialogues.TryAdd(dialogueData.Identity, dialogueData) is false) { dialogueData.Identity = _dialogues.Keys.Max() + 1; _dialogues.TryAdd(dialogueData.Identity, dialogueData); } try { await OnDialogueStart.UniTaskFunc(dialogueData) .AttachExternalCancellation(dialogueData.CancellationTokenSource.Token); } catch (OperationCanceledException) { } catch (OperationAbortedException) { } finally { dialogueData.CancellationTokenSource.Cancel(); OnDialogueEnd?.Invoke(dialogueData); } } public async UniTask CreateDialogue(IDialogueData dialogueData, IReadOnlyCollection dialogueChoices) { if (OnDialogueChoose is null) { throw new NullReferenceException("OnDialogueChoose is null,unable to create dialogue"); } var task = OnDialogueChoose.Invoke(dialogueData, dialogueChoices); var index = await task; OnDialogueChose?.Invoke(dialogueData, dialogueChoices.ElementAt(index)); return index; } public async UniTask CreateDynamicDialogue(IDialogueData dialogueData) { if (OnDynamicDialogueStartAsync is null)throw new Exception("OnDynamicDialogueStartAsync is not null"); OnDialogueStart?.Invoke(dialogueData); var result = await OnDynamicDialogueStartAsync.Invoke(dialogueData); OnDynamicDialogueEnd?.Invoke(dialogueData,result); return result; } private readonly ConcurrentDictionary _dialogues = new(); } }