using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using BITKit; using BITKit.Entities; using BITKit.Mod; using BITKit.UX; using Cysharp.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Net.BITKit.Chat; using Net.BITKit.Localization; using Net.Project.B.Dialogue; using Project.B.Player; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UIElements; namespace Net.Project.B.UX { public class UXDialogue:UIToolkitSubPanel, IUXDialogue where THud:IUXPanel { private readonly ILocalizationService _localizationService; private readonly IMainTicker _ticker; private readonly ILogger> _logger; private readonly IDialogueService _dialogueService; private readonly IChatService _chatService; private readonly ValidHandle _isBusy = new(); private VisualElement _rootVisualElement; private readonly IEntitiesService _entitiesService; [UXBindPath("dialogue-container")] private VisualElement _dialogueContainer; [UXBindPath("dialogue-choose-container")] private VisualElement _dialogueChooseContainer; [UXBindPath("comic-container")] private VisualElement _comicContainer; [UXBindPath("tips-foldout")] private Foldout _tipsFoldout; private readonly ValidHandle _allowTips = new(); private VisualElement _floatDialogueContainer; private VisualTreeAsset _dialogueTemplate; private VisualTreeAsset _dialogueChooseTemplate; private readonly ConcurrentDictionary _subtitles = new(); private UniTaskCompletionSource _chooseTask; private readonly ValidHandle _isVisible = new(); private readonly ValidHandle _allowComic = new(); private readonly ValidHandle _inDialogue = new(); private CancellationTokenSource _newDialogueCancellationTokenSource; private readonly IntervalUpdate _skipInterval = new (0.1f); private readonly ConcurrentDictionary _dialogues = new(); private readonly Dictionary _floatDialogues=new(); private readonly Dictionary _floatDialoguesGc = new(); private readonly IUXKeyMap _uxKeyMap; private readonly IPlayerKeyMap _playerKeyMap; public UXDialogue(IServiceProvider serviceProvider, IDialogueService dialogueService, ILogger> logger, IEntitiesService entitiesService, IMainTicker ticker, ILocalizationService localizationService, IUXKeyMap uxKeyMap, IPlayerKeyMap playerKeyMap, IChatService chatService) : base(serviceProvider) { _dialogueService = dialogueService; _logger = logger; _entitiesService = entitiesService; _ticker = ticker; _localizationService = localizationService; _uxKeyMap = uxKeyMap; _playerKeyMap = playerKeyMap; _chatService = chatService; _dialogueService.OnDialogueStart += OnDialogueStart; _dialogueService.OnDialogueEnd+=OnDialogueEnd; _dialogueService.OnDialogueChoose += OnDialogueChoose; _chatService.OnMessageReceived += OnMessageReceived; ticker.Add(Tick); } private void OnMessageReceived(ChatMessage obj) { if (obj.FromUserId == Environment.UserName) { _allowTips.Clear(); } } private void Tick(float obj) { foreach (var (id,visualElement) in _floatDialogues) { if(_entitiesService.TryGetEntity(id,out var entity) is false)continue; if (entity.ServiceProvider.QueryComponents(out Collider collider)) { visualElement.SetPosition(collider.bounds.center + Vector3.up * (collider.bounds.extents.y * 0.32f)); } else if (entity.ServiceProvider.QueryComponents(out Transform transform)) { visualElement.SetPosition(transform.position); } } } protected override async UniTask OnInitiatedAsync() { _logger.LogInformation("UX对话初始化中..."); using var _ = _isBusy.GetHandle(); _logger.LogInformation($"{typeof(THud).Name}已初始化完成,正在加载Template..."); _rootVisualElement = Panel.Root as VisualElement; UXUtils.Inject(this, _rootVisualElement); _dialogueContainer.Clear(); _dialogueChooseContainer.Clear(); _dialogueTemplate = await ModService.LoadAsset("ux_dialogue_template"); _dialogueChooseTemplate = await ModService.LoadAsset("ux_dialogue_choose_template"); _logger.LogInformation("UX对话初始化完成"); _dialogueContainer.SetActive(false); _isVisible.AddListener(_dialogueContainer.SetActive); _allowComic.AddListener(_comicContainer.SetActive); _allowComic?.Invoke(); if (Panel is UIToolKitPanel panel) { panel.InputActionGroup.RegisterCallback(_playerKeyMap.RunKey, OnConfirm); _floatDialogueContainer = panel.RootVisualElement.Create(); _floatDialogueContainer.pickingMode = PickingMode.Ignore; _floatDialogueContainer.style.position = new StyleEnum(Position.Absolute); _floatDialogueContainer.style.top = 0; _floatDialogueContainer.style.left = 0; _floatDialogueContainer.style.right = 0; _floatDialogueContainer.style.bottom = 0; _floatDialogueContainer.AddToClassList("ui_hud_dialogue_container"); _floatDialogueContainer.SendToBack(); } _allowTips.AddListener(x => { _tipsFoldout.Blur(); _tipsFoldout.schedule.Execute(() => { if (x) { _tipsFoldout.value = false; _tipsFoldout.SetActive(true); } else { _tipsFoldout.SetActive(false); _tipsFoldout.Clear(); } }); }); _tipsFoldout.Q().focusable = false; _allowTips.Invoke(); } private void OnConfirm(InputAction.CallbackContext obj) { if(_dialogues.Count is 0)return; if (obj.JustPressed() is false) return; if (Panel.Enabled is false) return; if (_skipInterval.AllowUpdateWithoutReset is false) return; foreach (var dialogue in _dialogues.Values.ToArray()) { dialogue.CancellationTokenSource.Cancel(); } throw new OperationCanceledException(); } private UniTask OnDialogueChoose(IDialogueData arg1, IReadOnlyCollection arg2) { BITAppForUnity.AllowCursor.AddElement(this); _chooseTask?.TrySetCanceled(); _chooseTask = new UniTaskCompletionSource(); _dialogueChooseContainer.Clear(); for (var i = 0; i < arg2.Count; i++) { var choice = arg2.ElementAt(i); var container = _dialogueChooseContainer.Create(_dialogueChooseTemplate); container.Get