Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/UX/UXInventorySwap.cs
2025-06-24 23:49:13 +08:00

296 lines
9.5 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using BITKit;
using BITKit.Entities;
using BITKit.Mod;
using BITKit.UX;
using BITKit.WorldNode;
using Cysharp.Threading.Tasks;
using Net.Project.B.Interaction;
using Net.Project.B.Inventory;
using Net.Project.B.Item;
using Net.Project.B.UX;
using Project.B.Entities;
using Project.B.Player;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
namespace Project.B.UX
{
public class UXInventorySwap : UIToolKitPanel,IUXInventorySwap
{
public override bool AllowCursor => true;
public override bool CloseWhenClickOutside => true;
private readonly IUXItemInspector _itemInspector;
private readonly IUXKeyMap<InputAction> _uxKeyMap;
private readonly IPlayerFactory _playerFactory;
private readonly IWorldInteractionService _interactionService;
private readonly IEntitiesService _entitiesService;
protected override string DocumentPath => "ui_inventory_swap";
private VisualTreeAsset _template;
[Inject]
private IPlayerInventory _playerInventory;
[UXBindPath("self-container")]
private VisualElement _selfContainer;
[UXBindPath("target-container")]
private VisualElement _targetContainer;
[UXBindPath("weapon-container",true)]
private VisualElement _weaponContainer;
[UXBindPath("preview-container", true)]
private VisualElement _previewContainer;
[UXBindPath("self-label")]
private Label _selfLabel;
[UXBindPath("target-label")]
private Label _targetLabel;
private IRuntimeItemContainer _targetItemContainer;
public UXInventorySwap(IUXService uxService, IPlayerFactory playerFactory, IWorldInteractionService interactionService, IEntitiesService entitiesService, IUXKeyMap<InputAction> uxKeyMap, IUXItemInspector itemInspector) : base(uxService)
{
_playerFactory = playerFactory;
_interactionService = interactionService;
_entitiesService = entitiesService;
_uxKeyMap = uxKeyMap;
_itemInspector = itemInspector;
OnInitiatedAsync += InitiatedAsync;
_playerFactory.OnEntityCreated += OnEntityCreated;
_interactionService.OnInteraction += OnInteraction;
}
private void OnInteraction(object arg1, IWorldInteractable arg2, WorldInteractionProcess arg3, object arg4)
{
if (arg3 is WorldInteractionProcess.Performed or WorldInteractionProcess.System is false) return;
if (_entitiesService.TryGetEntity(arg2.Id, out var entity) is false) return;
if (entity.ServiceProvider.QueryComponents(out IRuntimeItemContainer container) is false) return;
_targetItemContainer = container;
UXService.Entry(this);
}
private UniTask OnEntityCreated(string arg1, IEntity arg2)
{
arg2.Inject(this);
return UniTask.CompletedTask;
}
private async UniTask InitiatedAsync()
{
_template =await ModService.LoadAsset<VisualTreeAsset>("ux_item_template");
_weaponContainer ??= _targetContainer;
if (_previewContainer is not null)
{
_previewContainer.style.backgroundImage = null;
}
}
public override async UniTask EntryAsync()
{
_selfContainer.Clear();
_weaponContainer.Clear();
_targetContainer.Clear();
await base.EntryAsync();
await Rebuild();
}
private async UniTask Rebuild()
{
_selfContainer.Clear();
_weaponContainer.Clear();
_targetContainer.Clear();
if(_targetItemContainer is null)return;
foreach (var item in _playerInventory.Container.GetItems())
{
var container = _selfContainer.Create(_template);
container.parent.SetEnabled(_targetItemContainer.AllowAdd);
UXInventoryUtils.Setup(container, item).Forget();
container.Get<Button>().clicked += () =>
{
try
{
if (_playerInventory.Container.Remove(item.Id) is false)
{
return;
}
if (_targetItemContainer.Add(item) is false)
{
return;
}
}
catch (PlayerInventoryAddItemOverridden)
{
}
Rebuild().Forget();
};
Setup(container,item);
container.Get<Button>().RegisterCallback<MouseDownEvent>(evt =>
{
if(evt.button is not 1)return;
ContextMenuBuilder
.Create()
.BuildText("操作")
.BuildAction("检视", () =>_itemInspector.Inspect(item))
.BuildAction("丢下", () =>
{
if (_playerInventory.Container.Drop(item.Id))
{
Rebuild().Forget();
}
})
.Build();
});
}
foreach (var item in _targetItemContainer.GetItems())
{
var scriptableItem =await UXInventoryUtils.GetScriptableItem(item.ScriptableId);
var container =(scriptableItem is ScriptableWeapon{WeaponSlot:1 or 2} ? _weaponContainer : _targetContainer).Create(_template);
container.parent.SetEnabled(_targetItemContainer.AllowRemove);
UXInventoryUtils.Setup(container,item).Forget();
container.Get<Button>().clicked += Take;
Setup(container,item);
container.Get<Button>().RegisterCallback<MouseDownEvent>(evt =>
{
ContextMenuBuilder
.Create()
.BuildText("操作")
.BuildAction("检视", () =>_itemInspector.Inspect(item))
.BuildAction("拿起", Take)
.Build();
});
var isWide = scriptableItem is ScriptableWeapon { WeaponSlot: (int)PlayerWeaponSlot.Primary or (int)PlayerWeaponSlot.Secondary or (int)PlayerWeaponSlot.Sidearm};
if (isWide)
{
container.style.width = 200;
}
void Take()
{
try
{
if (_targetItemContainer.Remove(item.Id) is false)
{
return;
}
if (_playerInventory.Container.Add(item) is false)
{
return;
}
}
catch (PlayerInventoryAddItemOverridden)
{
}
Rebuild().Forget();
}
}
return;
void Setup(VisualElement container, IRuntimeItem runtimeItem)
{
if(_previewContainer is null)return;
async void Callback(PointerEnterEvent x)
{
var item = await UXInventoryUtils.GetScriptableItem(runtimeItem.ScriptableId);
_previewContainer.style.backgroundImage = new(item.Icon);
}
container.Get<Button>().RegisterCallback<PointerEnterEvent>(Callback);
}
}
protected override void OnPanelEntry()
{
base.OnPanelEntry();
InputActionGroup.RegisterCallback(_uxKeyMap.CancelKey, OnReturn);
InputActionGroup.RegisterCallback(_uxKeyMap.InventoryKey, OnReturn);
if (_targetItemContainer is not null)
{
_targetItemContainer.IsBusy.AddElement(this);
}
}
protected override void OnPanelExit()
{
base.OnPanelExit();
InputActionGroup.UnRegisterCallback(_uxKeyMap.CancelKey, OnReturn);
InputActionGroup.UnRegisterCallback(_uxKeyMap.InventoryKey, OnReturn);
_selfContainer.Clear();
_targetContainer.Clear();
_weaponContainer.Clear();
if (_targetItemContainer is not null)
{
_targetItemContainer.IsBusy.RemoveElement(this);
}
}
private void OnReturn(InputAction.CallbackContext obj)
{
if (obj.JustPressed() is false) return;
UXService.Return();
}
public override void Dispose()
{
base.Dispose();
OnInitiatedAsync -= InitiatedAsync;
_playerFactory.OnEntityCreated -= OnEntityCreated;
_interactionService.OnInteraction -= OnInteraction;
}
}
}