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

268 lines
9.0 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using BITKit;
using BITKit.Entities;
using BITKit.StateMachine;
using BITKit.UX;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Net.Project.B.Inventory;
using Net.Project.B.Item;
using Project.B.Entities;
using Project.B.Item;
using Project.B.Player;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.XR.Haptics;
using UnityEngine.UIElements;
namespace Net.Project.B.PDA
{
[Serializable]
public struct AppControllerClass : IScriptableControllerClass
{
}
public class UnityPDAService:UIToolKitPanel, IPDAService
{
private readonly IServiceProvider _serviceProvider;
private readonly IManagedItemService _managedItemService;
private readonly IUXKeyMap<InputAction> _uxKeyMap;
protected override string DocumentPath => "ui_pda";
public override bool AllowCursor => true;
public override bool CloseWhenClickOutside => true;
[UXBindPath("pda-container")] private VisualElement _pdaContainer;
[UXBindPath("dock-container")] private VisualElement _dockContainer;
[UXBindPath("app-container")] private VisualElement _appContainer;
[UXBindPath("home-button")] private Button _homeButton;
[Inject]
private IPlayerWeaponInventory _playerWeaponInventory;
[Inject] private IPlayerInventory _playerInventory;
private readonly HashSet<int> _pdaItems = new();
private VisualTreeAsset _appTemplate;
private readonly Dictionary<string,IAppClass> _routes = new();
private CancellationTokenSource _operatorCts = new();
private readonly ValidHandle _operatorHandle = new();
private readonly HashSet<object> _initiated = new();
private readonly Dictionary<string, VisualElement> _appLaunchers = new();
private IAppClass _currentAppClass;
private string _currentUrl;
public UnityPDAService(IUXService uxService, IPlayerFactory playerFactory, IEntitiesService entitiesService, IManagedItemService managedItemService, IUXKeyMap<InputAction> uxKeyMap, IServiceProvider serviceProvider) : base(uxService)
{
_managedItemService = managedItemService;
_uxKeyMap = uxKeyMap;
_serviceProvider = serviceProvider;
playerFactory.OnEntityCreated += OnEntityCreated;
foreach (var scriptableItem in entitiesService.QueryComponents<ScriptableItem>())
{
if (scriptableItem.ControllerClass is AppControllerClass)
{
_pdaItems.Add(scriptableItem.Id);
}
}
OnInitiatedAsync += InitiatedAsync;
foreach (var appClass in _serviceProvider.GetServices<IAppClass>())
{
foreach (var path in appClass.Routes)
{
_routes.Add(path,appClass);
}
}
}
private UniTask InitiatedAsync()
{
_appTemplate = _appContainer.Q<TemplateContainer>().templateSource;
_appContainer.Clear();
foreach (var appClass in _serviceProvider.GetServices<IAppClass>())
{
var app = (IApp)Activator.CreateInstance(appClass.AppType);
var container = _appContainer.Create(_appTemplate);
container.Get<Label>().text = app.AppName;
container.Get<VisualElement>().AddToClassList(app.PackageName.Replace(".", "-"));
container.Get<Button>().clicked += () =>
{
container.RemoveFromClassList("allow-badge");
var type = typeof(IAppClass<>).MakeGenericType(app.GetType());
var service = (IAppClass)_serviceProvider.GetRequiredService(type);
Navigate(service!.Routes[0]).Forget();
};
var packageName = Activator.CreateInstance(appClass.AppType).As<IApp>().PackageName;
_appLaunchers[packageName] = container;
}
_homeButton.clicked += ()=>Home().Forget();
#if UNITY_STANDALONE_WIN
var wallpaperPath = GetWindowsWallPaper.GetWallpaperPath();
if (System.IO.File.Exists(wallpaperPath))
{
byte[] imageData = System.IO.File.ReadAllBytes(wallpaperPath);
Texture2D texture = new Texture2D(2, 2);
if (texture.LoadImage(imageData))
{
RootVisualElement.Get<VisualElement>().style.backgroundImage = new StyleBackground(texture);
}
}
#endif
return UniTask.CompletedTask;
}
protected override void OnPanelEntry()
{
base.OnPanelEntry();
InputActionGroup.RegisterCallback(_uxKeyMap.CancelKey, OnCancel);
InputActionGroup.RegisterCallback(_uxKeyMap.InventoryKey, OnCancel);
}
private void OnCancel(InputAction.CallbackContext obj)
{
if (obj.JustPressed())
{
OnReturn();
}
}
protected override void OnPanelExit()
{
base.OnPanelExit();
InputActionGroup.UnRegisterCallback(_uxKeyMap.CancelKey, OnCancel);
InputActionGroup.UnRegisterCallback(_uxKeyMap.InventoryKey, OnCancel);
}
private UniTask OnEntityCreated(string arg1, IEntity arg2)
{
arg2.Inject(this);
_playerWeaponInventory.StateMachine.OnStateChanged += OnStateChanged;
return UniTask.CompletedTask;
}
private void OnStateChanged(IPlayerWeaponController arg1, IPlayerWeaponController arg2)
{
if(arg2 is null)return;
if(_managedItemService.Items.TryGetValue(arg2.Identifier,out var item) is false && _playerInventory.Container.ItemDictionary.TryGetValue(arg2.Identifier,out item) is false)return;
if(_pdaItems.Contains(item.ScriptableId) is false)return;
UXService.Entry(this);
}
public async UniTask Navigate(string url)
{
_operatorCts.Cancel();
_operatorCts = new();
await _operatorHandle;
using var _ = _operatorHandle.GetHandle();
if (_routes.TryGetValue(url, out var appClass) is false)return;
var prevClass = _currentAppClass;
if (prevClass is not null)
{
prevClass.Enabled = false;
await prevClass.OnStateExitAsync(prevClass,appClass);
prevClass.OnStateExit(prevClass,appClass);
}
if(_operatorCts.IsCancellationRequested)return;
_currentAppClass = appClass;
if (_initiated.Add(appClass))
{
await appClass.InitializeAsync();
appClass.Initialize();
}
appClass.Enabled = true;
var prevUrl = _currentUrl;
var page=await appClass.GetPage(_currentUrl = url);
if (page is VisualElement visualElement)
{
_pdaContainer.Add(visualElement);
}
appClass.OnStateEntryAsync(prevClass);
appClass.OnStateEntry(prevClass);
await OnNavigatedAsync.UniTaskFunc(prevUrl, url);
OnNavigated?.Invoke(prevUrl,url);
}
public async UniTask Home()
{
_operatorCts.Cancel();
_operatorCts = new();
await _operatorHandle;
using var _ = _operatorHandle.GetHandle();
if (_currentAppClass is not null)
{
_currentAppClass.Enabled = false;
await _currentAppClass.OnStateExitAsync(_currentAppClass,null);
_currentAppClass.OnStateExit(_currentAppClass,null);
_currentAppClass = null;
}
_pdaContainer.Clear();
}
public async UniTask Back()
{
_operatorCts.Cancel();
_operatorCts = new();
await _operatorHandle;
using var _ = _operatorHandle.GetHandle();
}
public void Badge(string packageName)
{
if (_currentAppClass is not null)
{
var app = Activator.CreateInstance(_currentAppClass.AppType).As<IApp>().PackageName;
if(string.Equals(app,packageName))return;
}
_appLaunchers[packageName].AddToClassList("allow-badge");
}
public event Action<string, string> OnNavigated;
public event Func<string, string, UniTask> OnNavigatedAsync;
public event Action<string> OnNotification;
public void Notify(string message)
{
OnNotification?.Invoke(message);
}
}
}