Net.Project.B/Src/Dialogue/IDialogueService.cs

139 lines
4.6 KiB
C#

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
{
/// <summary>
/// 对话服务
/// </summary>
public interface IDialogueService
{
/// <summary>
/// 所有对话
/// </summary>
IReadOnlyDictionary<int, IDialogueData> Dialogues { get; }
/// <summary>
/// 对话开始
/// </summary>
public event Func<IDialogueData, UniTask> OnDialogueStart;
public event Action<IDialogueData> OnDynamicDialogueStart;
/// <summary>
/// 动态对话
/// </summary>
public event Func<IDialogueData, UniTask<string>> OnDynamicDialogueStartAsync;
/// <summary>
/// 对话结束
/// </summary>
public event Action<IDialogueData> OnDialogueEnd;
/// <summary>
/// 动态对话结束
/// </summary>
public event Action<IDialogueData,string> OnDynamicDialogueEnd;
/// <summary>
/// 对话选择
/// </summary>
public event Func<IDialogueData, IReadOnlyCollection<IDialogueChoice>, UniTask<int>> OnDialogueChoose;
/// <summary>
/// 对话选择回调
/// </summary>
public event Action<IDialogueData, IDialogueChoice> OnDialogueChose;
/// <summary>
/// 开启对话
/// </summary>
/// <param name="dialogueData">对话</param>
/// <returns></returns>
UniTask CreateDialogue(IDialogueData dialogueData);
UniTask<int> CreateDialogue(IDialogueData dialogueData, IReadOnlyCollection<IDialogueChoice> dialogueChoices);
UniTask<string> CreateDynamicDialogue(IDialogueData dialogueData);
}
public class DialogueService : IDialogueService
{
public IReadOnlyDictionary<int, IDialogueData> Dialogues => _dialogues;
public event Func<IDialogueData, UniTask> OnDialogueStart;
public event Action<IDialogueData> OnDynamicDialogueStart;
public event Func<IDialogueData, UniTask<string>> OnDynamicDialogueStartAsync;
public event Action<IDialogueData> OnDialogueEnd;
public event Action<IDialogueData, string> OnDynamicDialogueEnd;
public event Func<IDialogueData, IReadOnlyCollection<IDialogueChoice>, UniTask<int>> OnDialogueChoose;
public event Action<IDialogueData, IDialogueChoice> 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<int> CreateDialogue(IDialogueData dialogueData,
IReadOnlyCollection<IDialogueChoice> 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<string> 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<int, IDialogueData> _dialogues = new();
}
}