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();
}
}