using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Threading; using AnotherFileBrowser.Windows; using BITKit.Mod; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.UIElements; namespace BITKit.UX { public class UXModService : MonoBehaviour { [SerializeField] private UIDocument document; [SerializeField] private VisualTreeAsset modTemplate; [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; private readonly ConcurrentDictionary _modContainers=new(); private void OnEnable() { ModService.OnModInstalled+=OnModInstalled; ModService.OnModUnInstalled+=OnModUnInstalled; ModService.OnModLoaded+=OnModLoaded; ModService.OnModUnLoaded+=OnModUnLoaded; ModService.OnLocked+=OnLocked; } private void OnDisable() { ModService.OnModInstalled-=OnModInstalled; ModService.OnModUnInstalled-=OnModUnInstalled; ModService.OnModLoaded-=OnModLoaded; ModService.OnModUnLoaded-=OnModUnLoaded; ModService.OnLocked-=OnLocked; } private void OnLocked(bool obj) { document.rootVisualElement.SetEnabled(!obj); } private void Start() { UXUtils.Inject(this); if (_openModButton is not null) { _openModButton.clicked += OpenMod; } if (_returnButton is not null) { _returnButton.clicked += UXService.Return; } _modsContainer.Clear(); foreach (var x in ModService.Mods) { OnModInstalled(x); } } private async void OnModUnInstalled(IMod obj) { await UniTask.SwitchToMainThread(); if (destroyCancellationToken.IsCancellationRequested) return; _modContainers.TryRemove(obj.Name, out var container); container.visualElement.SetEnabled(false); } private async void OnModInstalled(IMod obj) { await UniTask.SwitchToMainThread(); if (destroyCancellationToken.IsCancellationRequested) return; _modContainers.GetOrAdd(obj.Name,_=> Create(obj)); } private async void OnModUnLoaded(IMod obj) { await UniTask.SwitchToMainThread(); if (destroyCancellationToken.IsCancellationRequested) return; var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj)); container.toggle.SetValueWithoutNotify(false); } private async void OnModLoaded(IMod obj) { await UniTask.SwitchToMainThread(); if (destroyCancellationToken.IsCancellationRequested) return; var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj)); container.toggle.SetValueWithoutNotify(true); } private static void OpenMod() { new Thread(OpenModInternal).Start(); return; void OpenModInternal() { new FileBrowser().OpenFileBrowser(new BrowserProperties() { filter = "C Sharp files (*.cs)|*.cs", }, Filepath); return; async void Filepath(string path) { await BITApp.SwitchToMainThread(); var file = new FileInfo(path); switch (file.Extension) { case ".cs": var code = await File.ReadAllTextAsync(path); var assembly = BITSharp.Compile(code); await ModService.Load(assembly,Path.GetDirectoryName(path)); break; } } } } private UXContainer Create(IMod mod) { var container = new UXContainer(_modsContainer.Create(modTemplate)) { titleLabel = { text = mod.Name }, descriptionLabel = { text = mod.Description } }; container.toggle.RegisterValueChangedCallback(evt => { if (evt.newValue) { ModService.Load(mod); } else { ModService.UnLoad(mod); } }); container.visualElement.tooltip = mod.Name+"\n"+mod.Description; container.button.clicked += () => { _modNameLabel.text = mod.Name; _modDescriptionLabel.text = mod.Description; }; return container; } } }