356 lines
12 KiB
C#
356 lines
12 KiB
C#
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<UXHud> _logger;
|
|
|
|
private readonly IUXHotKey _hotKey;
|
|
private readonly ILocalizationService _localizationService;
|
|
private readonly IMicroStateMachine<IPlayerControlMode> _controlMode;
|
|
private readonly IEntitiesService _entitiesService;
|
|
private readonly IPlayerFactory _playerFactory;
|
|
private readonly IGameMapService _gameMapService;
|
|
private readonly IWorldInteractionService _interactionService;
|
|
private readonly IQuestService _questService;
|
|
private readonly IUXKeyMap<InputAction> _uxKeyMap;
|
|
|
|
public ValidHandle InCinematicMode { get; } = new();
|
|
|
|
[Inject]
|
|
private IEmojiService<AnimationClip> _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<VisualElement>();
|
|
|
|
private int _prevMuse;
|
|
|
|
public UXHud(IUXService uxService, IGameMapService gameMapService, IWorldInteractionService interactionService,
|
|
IQuestService questService, IPlayerFactory playerFactory,
|
|
IEntitiesService entitiesService, IUXKeyMap<InputAction> uxKeyMap,
|
|
IMicroStateMachine<IPlayerControlMode> controlMode, ILogger<UXHud> 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<VisualTreeAsset>("ux_quest_template");
|
|
|
|
_hiddenInControlMode = RootVisualElement.Query<VisualElement>(classes: "flex-non-control_mode").ToList().ToArray();
|
|
|
|
_logger.LogInformation("Hidden in control mode count:"+_hiddenInControlMode.Length);
|
|
|
|
Data.AddListener<int>("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<int>("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<GameObject>().GetInstanceID(), out var entity) &&
|
|
entity.ServiceProvider.GetService<WorldInfoNode>() 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<IUXHud>();
|
|
}
|
|
}
|
|
|
|
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<int, VisualElement> _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<LocalPlayerComponent,IBuffComponent>())
|
|
{
|
|
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<IUXMap>();
|
|
}else if (Keyboard.current is { f1Key: { wasPressedThisFrame: true } })
|
|
{
|
|
CreateEmojis();
|
|
}else if (Keyboard.current is { jKey: { wasPressedThisFrame: true } })
|
|
{
|
|
UXService.Entry<UXQuestList>();
|
|
}
|
|
}
|
|
|
|
|
|
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<Label>(0).text = quest.questData.Name;
|
|
visualElement.Get<Label>(1).text = quest.questData.Description;
|
|
|
|
_questContainers.TryAdd(quest.questData.Identity, visualElement);
|
|
}{}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private async void CreateEmojis()
|
|
{
|
|
var collection = new HotkeyCollection();
|
|
|
|
foreach (var emojiData in await _emojiService.GetAllEmojis())
|
|
{
|
|
collection.Register(new HotkeyProvider()
|
|
{
|
|
Name = emojiData.Name,
|
|
Description = emojiData.Description,
|
|
Enabled = true,
|
|
OnPerform = () => _emojiService.Play(emojiData),
|
|
});
|
|
}
|
|
|
|
_hotKey.Perform(collection);
|
|
}
|
|
|
|
protected override void OnPanelEntry()
|
|
{
|
|
base.OnPanelEntry();
|
|
InputActionGroup.RegisterCallback(_uxKeyMap.CancelKey, OnCancel);
|
|
InputActionGroup.RegisterCallback(_uxKeyMap.InventoryKey,OnInventory);
|
|
}
|
|
|
|
private void OnInventory(InputAction.CallbackContext obj)
|
|
{
|
|
if(obj.JustPressed() is false)return;
|
|
UXService.Entry<IUXInventory>();
|
|
}
|
|
|
|
private void OnCancel(InputAction.CallbackContext obj)
|
|
{
|
|
if (obj.JustPressed() is false) return;
|
|
UXService.Entry<UXEscMenu>();
|
|
}
|
|
|
|
protected override void OnPanelExit()
|
|
{
|
|
base.OnPanelExit();
|
|
InputActionGroup.UnRegisterCallback(_uxKeyMap.CancelKey, OnCancel);
|
|
InputActionGroup.UnRegisterCallback(_uxKeyMap.InventoryKey, OnInventory);
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
base.Dispose();
|
|
_singleton = null;
|
|
Data.RemoveListender<int>("yangdun_muse",OnInspiration);
|
|
}
|
|
|
|
}
|
|
|
|
}
|