using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using BITFALL; using BITFALL.Entities; using BITFALL.Entities.Equipment; using BITKit; using BITKit.Entities; using BITKit.Entities.Player; using BITKit.UX; using UnityEngine; using UnityEngine.UIElements; namespace bitfall.UX { public class UXPlayerEquipSelector : MonoBehaviour { [SerializeField] private UIDocument document; [SerializeField] private VisualTreeAsset equipmentVisualTreeAsset; [SerializeField] private VisualTreeAsset equipSelectorVisualTreeAsset; [SerializeReference, SubclassSelector] private IPlayerService _playerService; [Inject] private IPlayerEquipSelector _playerEquipSelector; [Inject] private IEntityEquipmentContainer _equipmentContainer; [Inject] private IEntityEquipment _equipment; [Inject] private IKnockdown _knockdown; [UXBindPath("equipment-container")] private VisualElement _equipmentContainerElement; [UXBindPath("equipSelector-container")] private VisualElement _equipSelectorContainerElement; private VisualElement _currentEquipElement; private readonly ConcurrentDictionary _equipmentContainerDictionary = new(); private readonly ConcurrentDictionary _equipSelectorContainerDictionary=new(); private void Start() { UXUtils.Inject(this); _playerService.OnPlayerInitialized += OnStartLocalPlayer; destroyCancellationToken.Register(() => _playerService.OnPlayerInitialized -= OnStartLocalPlayer); } private void OnStartLocalPlayer(Entity obj) { obj.Inject(this); _equipmentContainerElement.Clear(); _equipSelectorContainerElement.Clear(); _playerEquipSelector.OnUpdateEquip += OnUpdateEquip; _equipmentContainer.OnEquip += OnEquip; _equipmentContainer.OnDeEquip += OnDeEquip; _equipment.OnEquip += x => UpdateSelectorFocus(); _equipment.OnUnEquip += x => UpdateSelectorFocus(); _knockdown.OnKnockdown += UpdateSelectorFocus; _knockdown.OnRevive += UpdateSelectorFocus; } private void OnDeEquip(IEquipmentSlot arg1, IBasicItem arg2) { if (_equipmentContainerDictionary.TryRemove(arg2.AddressablePath, out var element) is false) return; element.RemoveFromHierarchy(); UpdateSelectorFocus(); } private void OnEquip(IEquipmentSlot arg1, IBasicItem arg2) { _equipmentContainerDictionary.GetOrAdd(arg2.AddressablePath, CreateEquipmentContainer); UpdateSelectorFocus(); } private void OnUpdateEquip(IDictionary obj) { _equipSelectorContainerElement.Clear(); _equipSelectorContainerDictionary.Clear(); foreach (var (index,x) in obj) { var element =_equipSelectorContainerDictionary.GetOrAdd(index,CreateEquipSelectorContainer(x.AddressablePath)); _equipSelectorContainerElement.Add(element); } UpdateSelectorFocus(); } private VisualElement CreateEquipmentContainer(string addressablePath) { var item = ItemExtensions.GetAssetable(addressablePath); var container = _equipmentContainerElement.Create(() => equipmentVisualTreeAsset.CloneTree()); var element = BITFALL.UX.UXUtils.CreateItemContainer(container, item); element.visualElement.userData = addressablePath; return element; } private VisualElement CreateEquipSelectorContainer(string addressablePath) { var item = ItemExtensions.GetAssetable(addressablePath); var container = _equipSelectorContainerElement.Create(() => equipSelectorVisualTreeAsset.CloneTree()); var element = BITFALL.UX.UXUtils.CreateItemContainer(container, item); if (item.RectangleIcon) element.icon.style.backgroundImage = item.RectangleIcon; element.visualElement.userData = addressablePath; return element; } private void UpdateSelectorFocus() { var current = _equipment.CurrentItem?.AddressablePath ?? string.Empty; const string active = "active"; _currentEquipElement?.RemoveFromHierarchy(); _currentEquipElement = _equipSelectorContainerElement.Create(equipSelectorVisualTreeAsset.CloneTree); _currentEquipElement.SetActive(false); var list = new List(); list.AddRange(_equipmentContainerElement.Children()); list.AddRange(_equipSelectorContainerElement.Children()); list.Add(_currentEquipElement); foreach (var visualElement in list.Where(visualElement => visualElement.userData is not null)) { visualElement.EnableInClassList(active,current == (string)visualElement.userData); var item = ItemExtensions.GetAssetable((string)visualElement.userData); visualElement.SetEnabled( !_knockdown.IsKnockdown || item.AllowUseWhileKnocked ); } if (_equipment.CurrentItem is not null && _playerEquipSelector.Equipped.Values.All(x => x.AddressablePath != _equipment.CurrentItem.AddressablePath)) { BITFALL.UX.UXUtils.CreateItemContainer(_currentEquipElement, _equipment.CurrentItem); _currentEquipElement.SetActive(true); } else { _currentEquipElement.SetActive(false); } } } }