using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using BITKit; using BITKit.Entities; using BITKit.Entities.Player; using Cysharp.Threading.Tasks; using JetBrains.Annotations; using NodeCanvas.DialogueTrees; using UnityEngine; using UnityEngine.InputSystem; namespace BITFALL.UX { /// /// 对话组件,基于NodeCanvas.DialogueTrees /// public class UXDialogue : MonoBehaviour { [SerializeReference,SubclassSelector] private IPlayerService playerService; [SerializeField] private UXBuilder dialogueBuilder; [SerializeField] private InputActionReference[] choosesActions; private readonly ValidHandle allowBackground = new(); private readonly List _dialogueIds = new(); [Inject] private InputActionGroup _inputActionGroup; [CanBeNull] private MultipleChoiceRequestInfo _multipleChoiceRequestInfo; private void Start() { allowBackground.AddListener(dialogueBuilder.VisualElement.SetActive); allowBackground.Invoke(); playerService.OnPlayerInitialized += OnPlayerInitialized; playerService.OnPlayerDisposed += OnPlayerDisposed; DialogueTree.OnSubtitlesRequest += OnSubtitlesRequest; DialogueTree.OnMultipleChoiceRequest += OnMultipleChoiceRequest; destroyCancellationToken.Register(() => { playerService.OnPlayerInitialized -= OnPlayerInitialized; DialogueTree.OnSubtitlesRequest -= OnSubtitlesRequest; DialogueTree.OnMultipleChoiceRequest -= OnMultipleChoiceRequest; playerService.OnPlayerDisposed -= OnPlayerDisposed; }); } private void OnPlayerDisposed(Entity obj) { foreach (var action in choosesActions) { UXOnScreenPrompts.Release(action.GetKeyMap()); } } private void OnPlayerInitialized(Entity obj) { obj.Inject(this); for (var i = 0; i < choosesActions.Length; i++) { var action = choosesActions[i]; var index = i; _inputActionGroup.RegisterCallback(action, OnAction); continue; void OnAction(InputAction.CallbackContext context) { if (_multipleChoiceRequestInfo is null) return; _multipleChoiceRequestInfo.SelectOption?.Invoke(index); _multipleChoiceRequestInfo = null; } } } private void OnMultipleChoiceRequest(MultipleChoiceRequestInfo obj) { _multipleChoiceRequestInfo = obj; foreach (var (statement,index) in obj.options) { UXOnScreenPrompts.Get(choosesActions[index].GetKeyMap(),statement.text); obj.SelectOption+=i => { UXOnScreenPrompts.Release(choosesActions[index].GetKeyMap()); }; } } private async void OnSubtitlesRequest(SubtitlesRequestInfo obj) { var id = obj.GetHashCode(); _dialogueIds.Add(id); dialogueBuilder.VisualElement.SetActive(true); var container = dialogueBuilder.BuildAsContainer(); container.contextLabel.text = $"{obj.actor.name}:{obj.statement}"; var tags = obj.statement.meta.ToLower().Split(","); try { var skip = tags.Contains("skip"); if (double.TryParse( obj.statement.meta,out var duration)) { await Task.Delay(TimeSpan.FromSeconds(duration), destroyCancellationToken); } else if(skip is false) { await Task.Delay(5000, destroyCancellationToken); } obj.Continue.Invoke(); await Task.Delay(5000, destroyCancellationToken); container.visualElement.AddToClassList("dispose"); await Task.Delay(1000, destroyCancellationToken); container.visualElement.RemoveFromHierarchy(); } catch (OperationCanceledException) { obj.Continue.Invoke(); } _dialogueIds.Remove(id); } private void Update() { allowBackground.SetElements(this, _dialogueIds.Count is not 0); } } }