1
This commit is contained in:
231
Src/Unity/Scripts/UX/ModService/UXModService.cs
Normal file
231
Src/Unity/Scripts/UX/ModService/UXModService.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
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;
|
||||
[UXBindPath("reload-mod-button",true)]
|
||||
private Button reloadModButton;
|
||||
|
||||
private readonly ConcurrentDictionary<string,UXContainer> _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);
|
||||
}
|
||||
|
||||
if (reloadModButton is not null)
|
||||
reloadModButton.clicked += async () =>
|
||||
{
|
||||
reloadModButton.SetEnabled(false);
|
||||
await ModService.Reload();
|
||||
if (destroyCancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
await UniTask.SwitchToMainThread();
|
||||
if (destroyCancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
reloadModButton.SetEnabled(true);
|
||||
};
|
||||
}
|
||||
|
||||
private async void OnModUnInstalled(IMod obj)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
if (destroyCancellationToken.IsCancellationRequested) return;
|
||||
_modContainers.TryRemove(obj.Name, out var container);
|
||||
container.visualElement.RemoveFromHierarchy();
|
||||
}
|
||||
|
||||
private async void OnModInstalled(IMod obj)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
if (destroyCancellationToken.IsCancellationRequested) return;
|
||||
var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj));
|
||||
container.visualElement.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();
|
||||
if (destroyCancellationToken.IsCancellationRequested) return;
|
||||
//var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj));
|
||||
if(_modContainers.TryGetValue(obj.Name,out var container))
|
||||
{
|
||||
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()
|
||||
{
|
||||
BIT4Log.Log("正在打开选择文件对话框");
|
||||
#if UNITY_EDITOR
|
||||
new Thread(OpenModInternal).Start();
|
||||
#else
|
||||
OpenModInternal();
|
||||
#endif
|
||||
|
||||
return;
|
||||
void OpenModInternal()
|
||||
{
|
||||
BIT4Log.Log<UXModService>("已进入文件对话框线程");
|
||||
new FileBrowser().OpenFileBrowser(new BrowserProperties()
|
||||
{
|
||||
//filterIndex = 0,
|
||||
//filter = "C Sharp files (*.cs)|*.cs |Dll files (*.dll)|*.dll",
|
||||
}, Filepath);
|
||||
return;
|
||||
async void Filepath(string path)
|
||||
{
|
||||
BIT4Log.Log<UXModService>("已选择文件:"+path);
|
||||
await BITApp.SwitchToMainThread();
|
||||
try
|
||||
{
|
||||
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;
|
||||
case ".dll":
|
||||
var bytes = await File.ReadAllBytesAsync(path);
|
||||
await ModService.Load(Assembly.Load(bytes),Path.GetDirectoryName(path));
|
||||
break;
|
||||
case ".json" when file.Name is ModPackage.DefaultFileName:
|
||||
await ModService.LoadFromPackage(path);
|
||||
break;
|
||||
default:
|
||||
Alert.Print(new AlertMessage()
|
||||
{
|
||||
title = "加载失败",
|
||||
message = "不支持的文件类型"
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Alert.Print(new AlertMessage()
|
||||
{
|
||||
title = "加载失败",
|
||||
message = e.Message
|
||||
});
|
||||
BIT4Log.LogException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user