BITKit/Src/Unity/Scripts/UX/ModService/UXModService.cs

169 lines
4.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
#if UNITY_5_3_OR_NEWER && UNITY_WINDOW
using AnotherFileBrowser.Windows;
#endif
using BITKit.Mod;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.UX
{
public class UXModService:UIToolKitPanel,IDisposable
{
protected override string DocumentPath => "ux_mod_Service";
private const string TemplatePath = "ux_mod_service_template";
public override bool AllowCursor => true;
private VisualTreeAsset _modTemplate;
[UXBindPath("open_folder-button")]
private Button _openFolderButton;
[UXBindPath("open-mod-button")]
private Button _openModButton;
[UXBindPath("mods-container")]
private VisualElement _modsContainer;
[UXBindPath("return-button")]
private Button _returnButton;
[UXBindPath("mod-name-label")]
private Label _modNameLabel;
[UXBindPath("mod-description-label")]
private Label _modDescriptionLabel;
[UXBindPath("reload-mod-button",true)]
private Button _reloadModButton;
[UXBindPath("install-roslyn-fill")]
private VisualElement _installRoslynFill;
private readonly ConcurrentDictionary<string,VisualElement> _modContainers=new();
public UXModService(IUXService uxService) : base(uxService)
{
ModService.OnModInstalled+=OnModInstalled;
ModService.OnModUnInstalled+=OnModUnInstalled;
ModService.OnModLoaded+=OnModLoaded;
ModService.OnModUnLoaded+=OnModUnLoaded;
ModService.IsBusy.AddListener(OnLocked);
OnInitiatedAsync += InitializeAsync;
}
private async UniTask InitializeAsync()
{
_installRoslynFill.style.width = 0;
_modTemplate =await ModService.LoadAsset<VisualTreeAsset>(TemplatePath);
UXUtils.Inject(this);
if (_returnButton is not null)
{
_returnButton.clicked += UXService.Return;
}
_modsContainer.Clear();
foreach (var x in ModService.Mods)
{
OnModInstalled(x);
}
if (_reloadModButton is not null)
_reloadModButton.clicked += async () =>
{
_reloadModButton.SetEnabled(false);
await ModService.Reload();
await UniTask.SwitchToMainThread();
_reloadModButton.SetEnabled(true);
};
_openFolderButton.clicked += () =>
{
new BITApp.OpenPath()
{
path = Path.Combine(Environment.CurrentDirectory, "Mods")
}.Execute();
};
}
private void OnLocked(bool obj)
{
RootVisualElement?.SetEnabled(!obj);
}
private async void OnModUnInstalled(IMod obj)
{
await UniTask.SwitchToMainThread();
_modContainers.TryRemove(obj.Name, out var container);
container.RemoveFromHierarchy();
}
private async void OnModInstalled(IMod obj)
{
await UniTask.SwitchToMainThread();
var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj));
container.RegisterCallback<MouseDownEvent>(x =>
{
if (x.button != 1) return;
ContextMenuBuilder.Create().BuildAction("卸载", () =>
{
ModService.UnLoad(obj);
ModService.UnInstall(obj);
}).Build();
});
}
private async void OnModUnLoaded(IMod obj)
{
await UniTask.SwitchToMainThread();
//var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj));
if(_modContainers.TryGetValue(obj.Name,out var container))
{
container.Get<Toggle>().SetValueWithoutNotify(false);
}
}
private async void OnModLoaded(IMod obj)
{
await UniTask.SwitchToMainThread();
var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj));
container.Get<Toggle>().SetValueWithoutNotify(true);
}
private VisualElement Create(IMod mod)
{
var container =_modsContainer.Create(_modTemplate);
container.Get<Toggle>().RegisterValueChangedCallback(evt =>
{
if (evt.newValue)
{
ModService.Load(mod);
}
else
{
ModService.UnLoad(mod);
}
});
container.tooltip = mod.Name+"\n"+mod.Description;
container.Get<Button>().clicked += () =>
{
_modNameLabel.text = mod.Name;
_modDescriptionLabel.text = mod.Description;
};
return container;
}
public void Dispose()
{
ModService.OnModInstalled-=OnModInstalled;
ModService.OnModUnInstalled-=OnModUnInstalled;
ModService.OnModLoaded-=OnModLoaded;
ModService.OnModUnLoaded-=OnModUnLoaded;
ModService.IsBusy.RemoveListener(OnLocked);
}
}
}