using System; using System.Collections; using System.Collections.Generic; using BITKit; using BITKit.Entities; using BITKit.Mod; using BITKit.StateMachine; using BITKit.UX; using BITKit.UX.Hotkey; using BITKit.WorldNode; using Cysharp.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Net.BITKit.Localization; using Net.BITKit.UX.SnackBar; using Net.Project.B.Buff; using Net.Project.B.Emoji; using Net.Project.B.Health; using Net.Project.B.Interaction; using Net.Project.B.Quest; using Net.Project.B.UX; using Project.B.Entities; using Project.B.Map; using Project.B.Player; using UnityEditor; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UIElements; namespace Net.Like.Xue.Tokyo.UX { public class UXHud : UIToolKitPanel,IUXHud { private static UXHud _singleton; private readonly ILogger _logger; private readonly IUXHotKey _hotKey; private readonly ILocalizationService _localizationService; private readonly IMicroStateMachine _controlMode; private readonly IEntitiesService _entitiesService; private readonly IPlayerFactory _playerFactory; private readonly IGameMapService _gameMapService; private readonly IWorldInteractionService _interactionService; private readonly IQuestService _questService; private readonly IUXKeyMap _uxKeyMap; public ValidHandle InCinematicMode { get; } = new(); [Inject] private IEmojiService _emojiService; [UXBindPath("inspiration-label")] private Label _inspirationLabel; [UXBindPath("muse-texture")] private VisualElement _museTexture; [UXBindPath("health-bar")] private ProgressBar _healthBar; [UXBindPath("hunger-bar")] private ProgressBar _hungerBar; [UXBindPath("thirsty-bar")] private ProgressBar _thirstyBar; private VisualElement[] _hiddenInControlMode=Array.Empty(); private int _prevMuse; public UXHud(IUXService uxService, IGameMapService gameMapService, IWorldInteractionService interactionService, IQuestService questService, IPlayerFactory playerFactory, IEntitiesService entitiesService, IUXKeyMap uxKeyMap, IMicroStateMachine controlMode, ILogger logger, ILocalizationService localizationService, IUXHotKey hotKey) : base(uxService) { if (_singleton is not null) { throw new Exception("Singleton already exists"); } _singleton = this; _gameMapService = gameMapService; _interactionService = interactionService; _questService = questService; _playerFactory = playerFactory; _entitiesService = entitiesService; _uxKeyMap = uxKeyMap; _controlMode = controlMode; _logger = logger; _localizationService = localizationService; _hotKey = hotKey; _gameMapService.OnMapChanged += OnMapChanged; _interactionService.OnInteraction += OnInteraction; _questService.OnQuestCreatedOrUpdated += (x, y, z) => _questQueue.Enqueue(new(x, y, z)); foreach (var (index, quest) in _questService.Quests) { _questQueue.Enqueue(new(quest, QuestState.Inactive, quest.CurrentState)); } _playerFactory.OnEntityCreated += OnEntityCreated; OnInitiatedAsync += InitiatedAsync; _controlMode.OnStateChanged += OnStateChanged; InCinematicMode.AddListener(x => { foreach (var visualElement in _hiddenInControlMode) { visualElement.SetActive(!x); } }); } private void OnInspiration(int obj) { if (obj > _prevMuse) { _museTexture.SetActive(true); _museTexture.schedule.Execute(() => _museTexture.SetActive(false)).ExecuteLater(3000); } _prevMuse = obj; if (_inspirationLabel is not null) _inspirationLabel.text = obj.ToString(); BITApp.ServiceProvider.QueryComponents(out ISnackBar snackBar); snackBar.Add($"Muse:{obj}"); } private void OnStateChanged(IPlayerControlMode arg1, IPlayerControlMode arg2) { InCinematicMode.SetElements(_controlMode,arg2 is not PlayerWalkMode); } private async UniTask InitiatedAsync() { _questContainer.Clear(); _questTemplate =await ModService.LoadAsset("ux_quest_template"); _hiddenInControlMode = RootVisualElement.Query(classes: "flex-non-control_mode").ToList().ToArray(); _logger.LogInformation("Hidden in control mode count:"+_hiddenInControlMode.Length); Data.AddListener("yangdun_muse", OnInspiration); } public override async UniTask OnStateEntryAsync(IState old) { await base.OnStateEntryAsync(old); InCinematicMode.Invoke(); } private UniTask OnEntityCreated(string arg1, IEntity arg2) { arg2.Inject(this); arg2.ServiceProvider.QueryComponents(out IHealthComponent healthComponent); healthComponent.OnHealthChanged += OnHealthChanged; OnHealthChanged(healthComponent.HealthPoint,healthComponent.HealthPoint); OnInspiration(Data.Get("yangdun_muse")); return UniTask.CompletedTask; } private void OnHealthChanged(int arg1, int arg2) { if (_healthBar is not null) { _healthBar.value = arg2; } } private void OnInteraction(object arg1, IWorldInteractable arg2, WorldInteractionProcess arg3, object arg4) { switch (arg3) { case WorldInteractionProcess.Hover: _interactionTips.SetActive(true); if (_entitiesService.Entities.TryGetValue( arg2.WorldObject.As().GetInstanceID(), out var entity) && entity.ServiceProvider.GetService() is { } infoNode && string.IsNullOrEmpty(infoNode.Name) is false) { _interactionTips.text =_localizationService.GetLocalizedString(infoNode.Name); } else { _interactionTips.text = _localizationService.GetLocalizedString("#Interaction"); } break; default: _interactionTips.SetActive(false); break; } } private void OnMapChanged(Guid arg1, string arg2) { if (string.IsNullOrEmpty(arg2) is false) { UXService.Entry(); } } protected override string DocumentPath => "ux_hud"; public override bool AllowInput => true; public override bool AllowCursor => false; [UXBindPath("interaction-tips")] private Label _interactionTips; [UXBindPath("quest-container")] private VisualElement _questContainer; private Camera _minimapCamera; private Camera _mainCamera; private VisualTreeAsset _questTemplate; private readonly Queue<(IQuestData questData, QuestState oldQuestState, QuestState newQuestState)> _questQueue = new(); private readonly Dictionary _questContainers = new(); public override async UniTask EntryAsync() { await base.EntryAsync(); _interactionTips.SetActive(false); } public override void OnTick(float deltaTime) { base.OnTick(deltaTime); if(RootVisualElement is null)return; foreach (var (_,buffComponent) in _entitiesService.QueryComponents()) { foreach (var buff in buffComponent.Buffs.Span) { switch (buff) { case Hunger: _hungerBar.value = buff.Value; break; case Thirsty: _thirstyBar.value = buff.Value; break; } } } if (BITInputSystem.AllowInput.Allow) { if (Keyboard.current is { capsLockKey: { wasPressedThisFrame: true } } or {mKey:{wasPressedThisFrame:true}}) { UXService.Entry(); }else if (Keyboard.current is { f1Key: { wasPressedThisFrame: true } }) { CreateEmojis(); }else if (Keyboard.current is { jKey: { wasPressedThisFrame: true } }) { UXService.Entry(); } } if (_questContainer is not null && _questTemplate!=null) { while (_questQueue.TryDequeue(out var quest)) { if (quest.questData.IsCompleted) { if (_questContainers.TryGetValue(quest.questData.Identity, out var visualElement)) { visualElement.RemoveFromHierarchy(); } } else { var visualElement = _questContainer.Create(_questTemplate); visualElement.Get