This commit is contained in:
parent
01e7e4e35e
commit
01b3d1be43
|
@ -8,19 +8,15 @@ namespace BITKit;
|
|||
|
||||
public class BITAppForNet
|
||||
{
|
||||
[Obsolete("Use InitializeAsync instead")]
|
||||
public static UniTask Init(string name)=>UniTask.CompletedTask;
|
||||
private static readonly Timer _timer = new();
|
||||
|
||||
private static Timer _timer = new();
|
||||
|
||||
private static DateTime _startTime = DateTime.UtcNow;
|
||||
private static readonly DateTime _startTime = DateTime.UtcNow;
|
||||
|
||||
public static async UniTask InitializeAsync(string name)
|
||||
{
|
||||
BIT4Log.OnLog += Console.WriteLine;
|
||||
BIT4Log.OnWarning += Console.WriteLine;
|
||||
BIT4Log.OnException += e => Console.WriteLine(e.ToString());
|
||||
BIT4Log.OnSetConsoleColor += color => Console.ForegroundColor = color;
|
||||
BIT4Log.OnNextLine += Console.WriteLine;
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
@ -15,44 +17,40 @@ namespace BITKit
|
|||
OnLog = null;
|
||||
OnException = null;
|
||||
OnWarning = null;
|
||||
OnSetConsoleColor = null;
|
||||
OnNextLine = null;
|
||||
}
|
||||
#endif
|
||||
public static event Action<string> OnLog;
|
||||
public static event Action<string,Type> OnLogCallback;
|
||||
public static event Action<Exception> OnException;
|
||||
public static event Action<Exception,Type> OnExceptionCallback;
|
||||
public static event Action<string> OnWarning;
|
||||
public static event Action<string,Type> OnWarningCallback;
|
||||
public static event Action<ConsoleColor> OnSetConsoleColor;
|
||||
public static event Action OnNextLine;
|
||||
private static Type currentType;
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
//[HideInCallstack]
|
||||
[HideInCallstack]
|
||||
#endif
|
||||
public static void Log(object x, ConsoleColor color = ConsoleColor.White)
|
||||
public static void Log(object x)
|
||||
{
|
||||
OnSetConsoleColor?.Invoke(color);
|
||||
OnLog?.Invoke(x?.ToString());
|
||||
OnLogCallback?.Invoke(x?.ToString(),currentType);
|
||||
if (OnLog is null)
|
||||
{
|
||||
BITApp.ServiceProvider.GetRequiredService<ILogger<BITApp>>().LogInformation(x.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
OnLog?.Invoke(x?.ToString());
|
||||
}
|
||||
}
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
[HideInCallstack]
|
||||
#endif
|
||||
public static void Log<T>(object x, ConsoleColor color = ConsoleColor.White)
|
||||
public static void Log<T>(object x)
|
||||
{
|
||||
if (currentType != typeof(T))
|
||||
if (OnLog is null)
|
||||
{
|
||||
OnNextLine?.Invoke();
|
||||
BITApp.ServiceProvider.GetRequiredService<ILogger<T>>().LogInformation(x.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
OnLog?.Invoke(x?.ToString());
|
||||
}
|
||||
#if NET5_0_OR_GREATER
|
||||
Log($"[{DateTime.Now}]{typeof(T).Name}:{x}");
|
||||
#else
|
||||
Log($"<color=#add8e6ff><b>{typeof(T).Name}</b></color>:{x}");
|
||||
#endif
|
||||
|
||||
currentType = typeof(T);
|
||||
}
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
[HideInCallstack]
|
||||
|
|
|
@ -126,7 +126,12 @@ namespace BITKit
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.LogException(e);
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Debug.LogException(e);
|
||||
#else
|
||||
BIT4Log.LogException(e);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -553,7 +553,6 @@ namespace BITKit.Net
|
|||
}
|
||||
if ((_now - startTime).TotalSeconds > RpcTimeOut)
|
||||
{
|
||||
await BITApp.SwitchToMainThread();
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new TimeoutException("请求超时或已断开连接");
|
||||
|
@ -561,7 +560,6 @@ namespace BITKit.Net
|
|||
}
|
||||
throw new TimeoutException($"请求超时或已断开连接,请求为{path}");
|
||||
}
|
||||
|
||||
|
||||
if (_p2p.TryRemove(id, out var value))
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace BITKit.Net
|
|||
KCPNet.Config
|
||||
);
|
||||
_timer.Elapsed += Tick;
|
||||
BIT4Log.Log<KCPNetServer>("已创建KCP服务器");
|
||||
//BIT4Log.Log<KCPNetServer>("已创建KCP服务器");
|
||||
|
||||
AddCommandListener<SimplePing>(F);
|
||||
|
||||
|
|
|
@ -130,10 +130,6 @@ namespace BITKit.Mod
|
|||
{
|
||||
public static async UniTask<ModPackage[]> SearchPackages()
|
||||
{
|
||||
//Todo
|
||||
IUXWaiting waiting = null;
|
||||
var handle = waiting?.Get();
|
||||
handle?.SetMessage("正在搜索Mod包");
|
||||
|
||||
var list=new List<ModPackage>();
|
||||
var path = Path.Combine(Environment.CurrentDirectory, "Mods");
|
||||
|
@ -149,7 +145,6 @@ namespace BITKit.Mod
|
|||
list.Add(package);
|
||||
}
|
||||
|
||||
waiting?.Release(handle);
|
||||
return list.ToArray();
|
||||
}
|
||||
public static async UniTask Reload()
|
||||
|
@ -184,16 +179,7 @@ namespace BITKit.Mod
|
|||
|
||||
public static IMod[] Mods { get; private set; }=Array.Empty<IMod>();
|
||||
|
||||
public static bool IsLocked
|
||||
{
|
||||
get => _IsLocked;
|
||||
set
|
||||
{
|
||||
if (_IsLocked == value) return;
|
||||
_IsLocked = value;
|
||||
OnLocked?.Invoke(value);
|
||||
}
|
||||
}
|
||||
public static readonly ValidHandle IsBusy = new();
|
||||
|
||||
public static event Action<ModPackage> OnPackageLoad;
|
||||
public static event Action<ModPackage> OnPackageLoaded;
|
||||
|
@ -207,179 +193,72 @@ namespace BITKit.Mod
|
|||
|
||||
public static event Action OnReload;
|
||||
public static event Action OnReloaded;
|
||||
|
||||
public static event Action<bool> OnLocked;
|
||||
|
||||
public static event Func<IMod,UniTask> OnModLoadAsync;
|
||||
public static event Func<IMod,UniTask> OnModUnloadAsync;
|
||||
|
||||
private static CancellationTokenSource _CancellationTokenSource;
|
||||
private static readonly ConcurrentQueue<IMod> _RegisterQueue=new();
|
||||
private static readonly ConcurrentQueue<IMod> _UnRegisterQueue = new();
|
||||
private static readonly List<IMod> _CacheMods = new();
|
||||
private static readonly ConcurrentDictionary<string,IMod> _InstalledMods=new();
|
||||
private static Thread _Thread;
|
||||
private static bool _IsRunning;
|
||||
private static bool _IsLocked;
|
||||
|
||||
public static void Initialize()
|
||||
public static async UniTask Initialize()
|
||||
{
|
||||
BIT4Log.Log<ModService>("Mod服务已启动");
|
||||
_IsRunning = true;
|
||||
_CancellationTokenSource = new CancellationTokenSource();
|
||||
_Thread = new Thread(InternalInitialize);
|
||||
_Thread.Start();
|
||||
|
||||
return;
|
||||
|
||||
async void InternalInitialize()
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
|
||||
try
|
||||
var modPath = Path.Combine(Environment.CurrentDirectory, "Mods\\");
|
||||
PathHelper.EnsureDirectoryCreated(modPath);
|
||||
var directoryInfo = new DirectoryInfo(modPath);
|
||||
foreach (var fileInfo in directoryInfo.GetFiles())
|
||||
{
|
||||
var modPath = Path.Combine(Environment.CurrentDirectory, "Mods\\");
|
||||
PathHelper.EnsureDirectoryCreated(modPath);
|
||||
var directoryInfo = new DirectoryInfo(modPath);
|
||||
foreach (var fileInfo in directoryInfo.GetFiles())
|
||||
switch (fileInfo.Extension)
|
||||
{
|
||||
switch (fileInfo.Extension)
|
||||
case ".dll":
|
||||
{
|
||||
case ".dll":
|
||||
{
|
||||
var assembly = Assembly.LoadFile(fileInfo.FullName);
|
||||
await Load(assembly);
|
||||
continue;
|
||||
}
|
||||
var assembly = Assembly.LoadFile(fileInfo.FullName);
|
||||
await Load(assembly);
|
||||
continue;
|
||||
}
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
case ".cs":
|
||||
{
|
||||
var code = await File.ReadAllTextAsync(fileInfo.FullName);
|
||||
var assembly = BITSharp.Compile(code);
|
||||
await Load(assembly, fileInfo.DirectoryName);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.Warning<ModService>("自动加载Mod失败");
|
||||
BIT4Log.LogException(e);
|
||||
}
|
||||
|
||||
|
||||
while (_IsRunning)
|
||||
{
|
||||
//todo
|
||||
IUXWaiting waiting = null;
|
||||
|
||||
_CacheMods.Clear();
|
||||
|
||||
while (_UnRegisterQueue.TryDequeue(out var mod))
|
||||
{
|
||||
var handle = waiting?.Get();
|
||||
handle?.SetMessage($":正在卸载{mod.PackageName}");
|
||||
|
||||
mod.OnDispose();
|
||||
_CacheMods.Add(mod);
|
||||
OnModUnLoad?.Invoke(mod);
|
||||
|
||||
waiting?.Release(handle);
|
||||
}
|
||||
|
||||
foreach (var mod in _CacheMods)
|
||||
{
|
||||
await mod.OnDisposeAsync(_CancellationTokenSource.Token);
|
||||
foreach (var x in OnModUnloadAsync.CastAsFunc())
|
||||
case ".cs":
|
||||
{
|
||||
await x.Invoke(mod);
|
||||
var code = await File.ReadAllTextAsync(fileInfo.FullName);
|
||||
var assembly = BITSharp.Compile(code);
|
||||
await Load(assembly, fileInfo.DirectoryName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var mod in _CacheMods)
|
||||
{
|
||||
mod.OnDisposed();
|
||||
OnModUnLoaded?.Invoke(mod);
|
||||
BIT4Log.Log<ModService>($"卸载Mod:{mod.GetType().FullName}");
|
||||
}
|
||||
|
||||
_CacheMods.Clear();
|
||||
|
||||
while (_RegisterQueue.TryDequeue(out var mod))
|
||||
{
|
||||
var handle = waiting?.Get();
|
||||
|
||||
handle?.SetMessage($"正在加载:{mod.PackageName}");
|
||||
|
||||
_CacheMods.Add(mod);
|
||||
mod.OnInitialize();
|
||||
OnModLoad?.Invoke(mod);
|
||||
BIT4Log.Log<ModService>($"加载Mod:{mod.GetType().FullName}");
|
||||
|
||||
waiting?.Release(handle);
|
||||
}
|
||||
|
||||
foreach (var mod in _CacheMods)
|
||||
{
|
||||
var handle = waiting?.Get();
|
||||
handle?.SetMessage($"正在初始化:{mod.PackageName}");
|
||||
|
||||
await mod.OnInitializedAsync(_CancellationTokenSource.Token);
|
||||
foreach (var x in OnModLoadAsync.CastAsFunc())
|
||||
{
|
||||
await x.Invoke(mod);
|
||||
}
|
||||
|
||||
waiting?.Release(handle);
|
||||
}
|
||||
|
||||
foreach (var mod in _CacheMods)
|
||||
{
|
||||
var handle = waiting?.Get();
|
||||
handle?.SetMessage($":正在完成初始化中{mod.PackageName}");
|
||||
|
||||
mod.OnInitialized();
|
||||
OnModLoaded?.Invoke(mod);
|
||||
|
||||
waiting?.Release(handle);
|
||||
}
|
||||
|
||||
_CacheMods.Clear();
|
||||
|
||||
|
||||
//Thread.Sleep(1000);
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
await UniTask.Delay(1000);
|
||||
#else
|
||||
await Task.Delay(1000);
|
||||
#endif
|
||||
IsLocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
BIT4Log.Log<ModService>("Mod服务已停止");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.Warning<ModService>("自动加载Mod失败");
|
||||
BIT4Log.LogException(e);
|
||||
BIT4Log.Warning<ModService>("Mod服务遇到了错误,已停止");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.LogException(e);
|
||||
BIT4Log.Warning<ModService>("Mod服务遇到了错误,已停止");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{_IsRunning = false;
|
||||
{
|
||||
_CancellationTokenSource.Cancel();
|
||||
try
|
||||
{
|
||||
_Thread.Join(100);
|
||||
_RegisterQueue.Clear();
|
||||
_UnRegisterQueue.Clear();
|
||||
Mods = Array.Empty<IMod>();
|
||||
_InstalledMods.Clear();
|
||||
}
|
||||
|
@ -387,8 +266,9 @@ namespace BITKit.Mod
|
|||
{
|
||||
BIT4Log.LogException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static UniTask Load(Assembly assembly,string folderPath=null)
|
||||
{
|
||||
BIT4Log.Log<ModService>($"加载程序集:{assembly.FullName}");
|
||||
|
@ -480,20 +360,35 @@ namespace BITKit.Mod
|
|||
}
|
||||
OnPackageLoaded?.Invoke(package);
|
||||
}
|
||||
public static void Load(IMod mod)
|
||||
public static async UniTask Load(IMod mod)
|
||||
{
|
||||
IsLocked = true;
|
||||
_RegisterQueue.Enqueue(mod);
|
||||
mod.OnInitialize();
|
||||
OnModLoad?.Invoke(mod);
|
||||
BIT4Log.Log<ModService>($"加载Mod:{mod.GetType().FullName}");
|
||||
}
|
||||
|
||||
public static void UnLoad(IMod mod)
|
||||
public static async UniTask UnLoad(IMod mod)
|
||||
{
|
||||
IsLocked = true;
|
||||
_UnRegisterQueue.Enqueue(mod);
|
||||
mod.OnDispose();
|
||||
OnModUnLoad?.Invoke(mod);
|
||||
|
||||
await mod.OnDisposeAsync(_CancellationTokenSource.Token);
|
||||
foreach (var x in OnModUnloadAsync.CastAsFunc())
|
||||
{
|
||||
await x.Invoke(mod);
|
||||
}
|
||||
|
||||
mod.OnDisposed();
|
||||
OnModUnLoaded?.Invoke(mod);
|
||||
BIT4Log.Log<ModService>($"卸载Mod:{mod.GetType().FullName}");
|
||||
}
|
||||
|
||||
public static void Install(IMod mod)
|
||||
public static async void Install(IMod mod)
|
||||
{
|
||||
await IsBusy;
|
||||
|
||||
using var _ = IsBusy.GetHandle();
|
||||
|
||||
if (_InstalledMods.ContainsKey(mod.PackageName))
|
||||
{
|
||||
throw new ArgumentException("Mod已安装");
|
||||
|
@ -501,9 +396,21 @@ namespace BITKit.Mod
|
|||
_InstalledMods.TryAdd(mod.PackageName,mod);
|
||||
Mods = _InstalledMods.Values.ToArray();
|
||||
OnModInstalled?.Invoke(mod);
|
||||
|
||||
await mod.OnInitializedAsync(_CancellationTokenSource.Token);
|
||||
foreach (var x in OnModLoadAsync.CastAsFunc())
|
||||
{
|
||||
await x.Invoke(mod);
|
||||
}
|
||||
|
||||
mod.OnInitialized();
|
||||
OnModLoaded?.Invoke(mod);
|
||||
}
|
||||
public static void UnInstall(IMod mod)
|
||||
{
|
||||
using var _ = IsBusy.GetHandle();
|
||||
|
||||
|
||||
if(_InstalledMods.ContainsKey(mod.PackageName) is false) return;
|
||||
_InstalledMods.TryRemove(mod.PackageName);
|
||||
Mods = _InstalledMods.Values.ToArray();
|
||||
|
|
|
@ -103,10 +103,11 @@ namespace BITKit
|
|||
if (IsSyncContext)
|
||||
{
|
||||
await BITApp.SwitchToMainThread();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
await BITApp.SwitchToMainThread();
|
||||
if (UnityEditor.EditorApplication.isPaused)
|
||||
{
|
||||
_timer.Interval = 1000d / TickRate;
|
||||
_timer.Start();
|
||||
return;
|
||||
}
|
||||
|
@ -164,12 +165,19 @@ namespace BITKit
|
|||
TickCount++;
|
||||
|
||||
if(_isDisposed)return;
|
||||
_timer.Interval = 1000d / TickRate;
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
public bool IsSyncContext { get; set; } = true;
|
||||
public ulong TickCount { get; set; }
|
||||
public int TickRate { get; set; }
|
||||
|
||||
public int TickRate
|
||||
{
|
||||
get => _tickRate;
|
||||
set => _tickRate = Math.Clamp(value, 1, int.MaxValue);
|
||||
}
|
||||
private int _tickRate;
|
||||
public bool IsConcurrent { get; set; }
|
||||
public event Func<float, UniTask> OnTickAsync;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace BITKit.UX
|
|||
/// </summary>
|
||||
public interface IUXService:IDisposable
|
||||
{
|
||||
public string SettingsPath { get; set; }
|
||||
object Root { get; }
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
|
@ -87,7 +88,7 @@ namespace BITKit
|
|||
public readonly List<object> disableObjs = new List<object>();
|
||||
private bool tempEnable;
|
||||
private Action<bool> EventOnEnableChanged;
|
||||
private readonly Queue<UniTaskCompletionSource> _completionSources = new();
|
||||
private readonly ConcurrentQueue<UniTaskCompletionSource> _completionSources = new();
|
||||
private bool _isDisposed;
|
||||
|
||||
public void AddElement(object obj)
|
||||
|
|
|
@ -228,9 +228,24 @@ namespace BITKit.Console
|
|||
_commandSelector.SetMethods(null);
|
||||
}
|
||||
}
|
||||
private async void OnKeyDown(KeyDownEvent keyDownEvent)
|
||||
private bool _stopNextFrame;
|
||||
private void OnKeyDown(KeyDownEvent keyDownEvent)
|
||||
{
|
||||
var nextStop=true;
|
||||
if (_stopNextFrame)
|
||||
{
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
_stopNextFrame = false;
|
||||
}
|
||||
|
||||
|
||||
if (keyDownEvent.keyCode is KeyCode.BackQuote)
|
||||
{
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
_stopNextFrame = true;
|
||||
return;
|
||||
}
|
||||
switch (keyDownEvent.keyCode)
|
||||
{
|
||||
case KeyCode.Return:
|
||||
|
@ -240,35 +255,30 @@ namespace BITKit.Console
|
|||
|
||||
_textField.SetValueWithoutNotify(string.Empty);
|
||||
|
||||
await UniTask.NextFrame();
|
||||
|
||||
_textField.Blur();
|
||||
|
||||
_textField.Focus();
|
||||
|
||||
BITCommands.Excute(cmd);
|
||||
|
||||
_commandSelector.SetMethods(null);
|
||||
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
_stopNextFrame = true;
|
||||
break;
|
||||
case KeyCode.Tab:
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
break;
|
||||
case KeyCode.DownArrow when string.IsNullOrEmpty(_textField.text) is false:
|
||||
_commandSelector.Index-=1;
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
break;
|
||||
case KeyCode.UpArrow when string.IsNullOrEmpty(_textField.text) is false:
|
||||
_commandSelector.Index+=1;
|
||||
break;
|
||||
default:
|
||||
nextStop = false;
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
break;
|
||||
}
|
||||
|
||||
if (nextStop)
|
||||
{
|
||||
keyDownEvent.StopPropagation();
|
||||
keyDownEvent.PreventDefault();
|
||||
}
|
||||
}
|
||||
private async void LogCallback(string condition, string stackTrace, LogType type)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace BITKit
|
|||
}
|
||||
public sealed class UnityLogger<T>:ILogger<T>
|
||||
{
|
||||
[HideInCallstack]
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
switch (logLevel)
|
||||
|
@ -56,7 +57,7 @@ namespace BITKit
|
|||
}
|
||||
break;
|
||||
default:
|
||||
Debug.Log($"<color=cyan>{typeof(T).Name}</color>:{state.ToString()}");
|
||||
Debug.Log($"<b>{typeof(T).Name}</b>:{state.ToString()}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace BITKit
|
|||
|
||||
private void LateUpdate()
|
||||
{
|
||||
LateUpdateTick?.Invoke(Time.deltaTime);
|
||||
LateUpdateTick?.Invoke(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ using UnityEngine;
|
|||
using UnityEngine.UIElements;
|
||||
using UnityEngine.InputSystem;
|
||||
using BITKit.Mod;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace BITKit.UX.Internal
|
||||
|
@ -111,7 +112,7 @@ namespace BITKit.UX
|
|||
private readonly IUXService _uxService;
|
||||
private VisualElement _root;
|
||||
private VisualElement _container;
|
||||
private bool _isInitialized = false;
|
||||
private readonly UniTaskCompletionSource _waitUntilInitialized = new();
|
||||
public UXContextMenu(IUXService uxService)
|
||||
{
|
||||
_uxService = uxService;
|
||||
|
@ -144,11 +145,14 @@ namespace BITKit.UX
|
|||
{
|
||||
Close();
|
||||
});
|
||||
_isInitialized = true;
|
||||
|
||||
_waitUntilInitialized.TrySetResult();
|
||||
|
||||
Close();
|
||||
}
|
||||
public void Create(ContextMenuBuilder builder)
|
||||
public async void Create(ContextMenuBuilder builder)
|
||||
{
|
||||
await _waitUntilInitialized.Task;
|
||||
var pos = Mouse.current.position.ReadValue();
|
||||
pos.y = Screen.height - pos.y;
|
||||
pos = RuntimePanelUtils.ScreenToPanel(_root.panel, pos);
|
||||
|
@ -166,9 +170,9 @@ namespace BITKit.UX
|
|||
}
|
||||
builder.OnExecuted += Close;
|
||||
}
|
||||
private void Close()
|
||||
private async void Close()
|
||||
{
|
||||
if(_isInitialized is false)return;
|
||||
await _waitUntilInitialized.Task;
|
||||
_container.Clear();
|
||||
_root.SetActive(false);
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ namespace BITKit.UX
|
|||
var tabName = split[i];
|
||||
var index = i;
|
||||
var button = _buttons[i] = this.Create<Button>();
|
||||
button.AddToClassList("v"+i);
|
||||
button.text = tabName;
|
||||
button.focusable = allowFocus;
|
||||
button.clicked += () => CurrentTab = index;
|
||||
|
|
|
@ -25,50 +25,48 @@ namespace BITKit.UX
|
|||
public new class UxmlFactory : UxmlFactory<TabContainer, UxmlTraits> { }
|
||||
public TabContainer()
|
||||
{
|
||||
RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
|
||||
RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
|
||||
RegisterCallback<AttachToPanelEvent>(RebuildOnEvent);
|
||||
RegisterCallback<DetachFromPanelEvent>(RebuildOnEvent);
|
||||
RegisterCallback<GeometryChangedEvent>(RebuildOnEvent);
|
||||
RegisterCallback<BlurEvent>(RebuildOnEvent);
|
||||
RegisterCallback<FocusEvent>(RebuildOnEvent);
|
||||
}
|
||||
|
||||
private void OnGeometryChanged(GeometryChangedEvent evt)
|
||||
{
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
public string TabPath
|
||||
{
|
||||
get=>_tabPath;
|
||||
set
|
||||
{
|
||||
_tabPath = value;
|
||||
Rebuild();
|
||||
}
|
||||
}
|
||||
private string _tabPath;
|
||||
private TabBar _tabBar;
|
||||
private int _index;
|
||||
private void OnDetachFromPanel(DetachFromPanelEvent evt)
|
||||
private void RebuildOnEvent<T>(T evt)
|
||||
{
|
||||
Rebuild();
|
||||
}
|
||||
private void OnAttachToPanel(AttachToPanelEvent evt)
|
||||
{
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
private void Rebuild()
|
||||
{
|
||||
if (_tabBar is not null)
|
||||
{
|
||||
_tabBar.OnTabChanged -= OnTabChanged;
|
||||
}
|
||||
_tabBar = panel.visualTree.Q<TabBar>(TabPath);
|
||||
var p = parent;
|
||||
while (p is not null)
|
||||
{
|
||||
_tabBar = p.Q<TabBar>(TabPath);
|
||||
if (_tabBar is not null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p = p.parent;
|
||||
}
|
||||
if (_tabBar is not null)
|
||||
{
|
||||
_tabBar.OnTabChanged += OnTabChanged;
|
||||
}
|
||||
if (_index <=0)
|
||||
{
|
||||
_index = 1;
|
||||
_index = _tabBar.CurrentTab;
|
||||
}
|
||||
OnTabChanged(_index);
|
||||
}
|
||||
|
@ -76,7 +74,7 @@ namespace BITKit.UX
|
|||
private void OnTabChanged(int obj)
|
||||
{
|
||||
_index = obj;
|
||||
if (childCount <= 0) return;
|
||||
if (childCount < 0) return;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
var visualElement = this[i];
|
||||
|
|
|
@ -21,16 +21,10 @@ namespace BITKit.UX
|
|||
private const string TemplatePath = "ux_mod_service_template";
|
||||
public override bool AllowCursor => true;
|
||||
|
||||
public UXModService(IUXService uxService) : base(uxService)
|
||||
{
|
||||
ModService.OnModInstalled+=OnModInstalled;
|
||||
ModService.OnModUnInstalled+=OnModUnInstalled;
|
||||
ModService.OnModLoaded+=OnModLoaded;
|
||||
ModService.OnModUnLoaded+=OnModUnLoaded;
|
||||
ModService.OnLocked+=OnLocked;
|
||||
}
|
||||
|
||||
private VisualTreeAsset _modTemplate;
|
||||
|
||||
[UXBindPath("open_folder-button")]
|
||||
private Button _openFolderButton;
|
||||
[UXBindPath("open-mod-button")]
|
||||
private Button _openModButton;
|
||||
[UXBindPath("mods-container")]
|
||||
|
@ -43,22 +37,27 @@ namespace BITKit.UX
|
|||
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);
|
||||
|
||||
private void OnLocked(bool obj)
|
||||
{
|
||||
RootVisualElement?.SetEnabled(!obj);
|
||||
OnInitiatedAsync += InitializeAsync;
|
||||
}
|
||||
public override async UniTask EntryAsync()
|
||||
|
||||
private async UniTask InitializeAsync()
|
||||
{
|
||||
await base.EntryAsync();
|
||||
_installRoslynFill.style.width = 0;
|
||||
|
||||
_modTemplate =await ModService.LoadAsset<VisualTreeAsset>(TemplatePath);
|
||||
UXUtils.Inject(this);
|
||||
if (_openModButton is not null)
|
||||
{
|
||||
_openModButton.clicked += OpenMod;
|
||||
}
|
||||
|
||||
if (_returnButton is not null)
|
||||
{
|
||||
|
@ -79,7 +78,22 @@ namespace BITKit.UX
|
|||
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();
|
||||
|
@ -117,78 +131,6 @@ namespace BITKit.UX
|
|||
var container = _modContainers.GetOrAdd(obj.Name,_=> Create(obj));
|
||||
container.Get<Toggle>().SetValueWithoutNotify(true);
|
||||
}
|
||||
|
||||
private static void OpenMod()
|
||||
{
|
||||
BIT4Log.Log("正在打开选择文件对话框");
|
||||
#if UNITY_EDITOR
|
||||
new Thread(OpenModInternal).Start();
|
||||
#else
|
||||
OpenModInternal();
|
||||
#endif
|
||||
|
||||
return;
|
||||
void OpenModInternal()
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER && UNITY_WINDOW
|
||||
BIT4Log.Log<UXModService>("已进入文件对话框线程");
|
||||
new FileBrowser().OpenFileBrowser(new BrowserProperties()
|
||||
{
|
||||
//filterIndex = 0,
|
||||
//filter = "C Sharp files (*.cs)|*.cs |Dll files (*.dll)|*.dll",
|
||||
}, Filepath);
|
||||
#else
|
||||
throw new NotSupportedException($"{Application.platform} 不支持打开文件对话框");
|
||||
#endif
|
||||
return;
|
||||
async void Filepath(string path)
|
||||
{
|
||||
BIT4Log.Log<UXModService>("已选择文件:"+path);
|
||||
await BITApp.SwitchToMainThread();
|
||||
try
|
||||
{
|
||||
var file = new FileInfo(path);
|
||||
|
||||
switch (file.Extension)
|
||||
{
|
||||
case ".cs":
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
var code = await File.ReadAllTextAsync(path);
|
||||
var assembly = BITSharp.Compile(code);
|
||||
await ModService.Load(assembly,Path.GetDirectoryName(path));
|
||||
#else
|
||||
throw new NotSupportedException($"{Application.platform} 不支持编译C#代码");
|
||||
#endif
|
||||
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 VisualElement Create(IMod mod)
|
||||
{
|
||||
var container =_modsContainer.Create(_modTemplate);
|
||||
|
@ -219,7 +161,7 @@ namespace BITKit.UX
|
|||
ModService.OnModUnInstalled-=OnModUnInstalled;
|
||||
ModService.OnModLoaded-=OnModLoaded;
|
||||
ModService.OnModUnLoaded-=OnModUnLoaded;
|
||||
ModService.OnLocked-=OnLocked;
|
||||
ModService.IsBusy.RemoveListener(OnLocked);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ using Debug = UnityEngine.Debug;
|
|||
|
||||
namespace BITKit.UX
|
||||
{
|
||||
public abstract class UIToolKitPanel : IUXPanel
|
||||
public abstract class UIToolKitPanel : IUXPanel,IDisposable
|
||||
{
|
||||
public const string USSEntry = "transition_entry";
|
||||
public const string USSEntryAsync = "transition_entry_async";
|
||||
|
@ -128,6 +128,7 @@ namespace BITKit.UX
|
|||
public virtual bool AllowCursor { get; }
|
||||
public virtual bool AllowInput { get; }
|
||||
public virtual string[] InitialUssClasses { get; } = Array.Empty<string>();
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public bool IsEntered { get; set; }
|
||||
protected virtual void OnReturn()
|
||||
|
@ -247,6 +248,12 @@ namespace BITKit.UX
|
|||
public virtual void OnTick(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
RootVisualElement?.RemoveFromHierarchy();
|
||||
IsDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace BITKit.UX
|
|||
protected readonly IUXService UXService;
|
||||
protected VisualElement RootVisualElement { get; set; }
|
||||
protected bool IsInitialized { get; private set; }
|
||||
protected readonly UniTaskCompletionSource WaitUntilInitialized = new();
|
||||
protected UIToolkitOverlay(IUXService uxService, CancellationTokenSource cancellationToken)
|
||||
{
|
||||
UXService = uxService;
|
||||
|
@ -40,6 +41,8 @@ namespace BITKit.UX
|
|||
|
||||
UXUtils.Inject(this);
|
||||
IsInitialized = true;
|
||||
|
||||
WaitUntilInitialized.TrySetResult();
|
||||
}
|
||||
public virtual void Dispose()
|
||||
{
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace BITKit.UX
|
|||
/// </summary>
|
||||
public static void ClearHistory() => History.Clear();
|
||||
|
||||
public string SettingsPath { get; set; } = "ux_panel_settings";
|
||||
public object Root { get; private set; }
|
||||
public async UniTask InitializeAsync()
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ Object.Destroy(gameObject);
|
|||
var document = gameObject.AddComponent<UIDocument>();
|
||||
try
|
||||
{
|
||||
var panelSettings =await ModService.LoadAsset<PanelSettings>("ux_panel_settings");
|
||||
var panelSettings =await ModService.LoadAsset<PanelSettings>(SettingsPath);
|
||||
document.panelSettings = panelSettings;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -102,7 +102,16 @@ namespace BITKit
|
|||
handle.VisualElement.RemoveFromHierarchy();
|
||||
_visibleHandle.RemoveElement(handle);
|
||||
}
|
||||
_visibleHandle.Invoke();
|
||||
|
||||
try
|
||||
{
|
||||
_visibleHandle.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async UniTask InitializeAsync()
|
||||
|
@ -116,6 +125,8 @@ namespace BITKit
|
|||
|
||||
UXUtils.Inject(this);
|
||||
_container.Clear();
|
||||
|
||||
_visibleHandle.Invoke();
|
||||
|
||||
_initializationState = InitializationState.Initialized;
|
||||
}
|
||||
|
|
|
@ -714,5 +714,48 @@ namespace BITKit
|
|||
|
||||
self.SetOpacity(visible ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void ClearTooltipsOnPointerLeave(this VisualElement visualElement)
|
||||
{
|
||||
visualElement.RegisterCallback<PointerLeaveEvent>(OnLeave);
|
||||
return;
|
||||
|
||||
void OnLeave(PointerLeaveEvent evt)
|
||||
{
|
||||
if (string.IsNullOrEmpty(visualElement.tooltip) is false)
|
||||
visualElement.tooltip = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static void BlinkingCursor(this TextField tf,int interval=1000)
|
||||
{
|
||||
tf.schedule.Execute(() =>
|
||||
{
|
||||
if(tf.ClassListContains("transparentCursor"))
|
||||
tf.RemoveFromClassList("transparentCursor");
|
||||
else
|
||||
tf.AddToClassList("transparentCursor");
|
||||
}).Every(interval);
|
||||
}
|
||||
public static Vector2 GetAbsolutePositionInUI(this VisualElement element)
|
||||
{
|
||||
var position = Vector2.zero;
|
||||
var currentElement = element;
|
||||
|
||||
// 遍历每一个父元素,并累计位置
|
||||
while (currentElement != null)
|
||||
{
|
||||
var style = currentElement.resolvedStyle;
|
||||
|
||||
// 累加该元素相对于父元素的位置
|
||||
position.x += style.left;
|
||||
position.y += style.top;
|
||||
|
||||
// 移动到父元素
|
||||
currentElement = currentElement.parent;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ MonoBehaviour:
|
|||
m_FallbackDpi: 96
|
||||
m_ReferenceResolution: {x: 1920, y: 1080}
|
||||
m_ScreenMatchMode: 0
|
||||
m_Match: 0.421
|
||||
m_Match: 0.5
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
m_ClearDepthStencil: 1
|
||||
|
|
|
@ -93,6 +93,37 @@ TabBar Button:disabled {
|
|||
margin-left: 32px;
|
||||
}
|
||||
|
||||
.gap-8 {
|
||||
margin-top: -8px;
|
||||
margin-right: -8px;
|
||||
margin-bottom: -8px;
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.gap-8 > * {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.gap-x-8 {
|
||||
margin-right: -8px;
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.gap-x-8 > * {
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.gap-y-8 {
|
||||
margin-top: -8px;
|
||||
margin-bottom: -8px;
|
||||
}
|
||||
|
||||
.gap-y-8 > * {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.r-8 {
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
|
@ -473,3 +504,7 @@ Button.clear {
|
|||
border-top-color: rgba(0, 0, 0, 0);
|
||||
border-bottom-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
TabContainer > * {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<ui:Template name="ModTemplate" src="project://database/Assets/BITKit/Unity/UX/ModTemplate.uxml?fileID=9197481963319205126&guid=5d8350eb5da74b34a81d90d7fdea10c7&type=3#ModTemplate" />
|
||||
<ui:Template name="ModTemplate" src="project://database/Assets/BITKit/Unity/UX/ux_mod_service_template.uxml?fileID=9197481963319205126&guid=5d8350eb5da74b34a81d90d7fdea10c7&type=3#ux_mod_service_template" />
|
||||
<Style src="project://database/Assets/BITKit/Unity/UX/Common/Common.uss?fileID=7433441132597879392&guid=a3a69d3518fd02b489e721f3c5b0b539&type=3#Common" />
|
||||
<Style src="project://database/Assets/BITKit/Unity/UX/UXModService.uss?fileID=7433441132597879392&guid=4603eeaf39bae3448a93680711a15c42&type=3#UXModService" />
|
||||
<Style src="project://database/Assets/BITKit/Unity/UX/BITAlert.uss?fileID=7433441132597879392&guid=8d0db0fee932f5342988f09217d6309a&type=3#BITAlert" />
|
||||
|
@ -31,12 +31,13 @@
|
|||
<ui:VisualElement style="width: 384px; margin-left: 64px;">
|
||||
<ui:Label tabindex="-1" text="Mod列表" parse-escape-sequences="true" display-tooltip-when-elided="true" class="tl" />
|
||||
<ui:VisualElement name="info-container" style="flex-grow: 1;">
|
||||
<ui:VisualElement name="mod-image" style="height: 256px; background-color: rgba(0, 0, 0, 0); background-image: url('project://database/Assets/BITKit/Unity/Art/Images/Mod_Package.png?fileID=2800000&guid=7ef0888883a3a7442989365c2dc57862&type=3#Mod_Package'); -unity-background-scale-mode: scale-and-crop;" />
|
||||
<ui:VisualElement name="mod-image" style="height: 256px; background-color: rgba(0, 0, 0, 0); background-image: url("project://database/Assets/BITKit/Unity/Art/Images/Mod_Package.png?fileID=2800000&guid=7ef0888883a3a7442989365c2dc57862&type=3#Mod_Package"); -unity-background-scale-mode: scale-and-crop;" />
|
||||
<ui:VisualElement style="padding-top: 8px; padding-right: 0; padding-bottom: 8px; padding-left: 0; flex-grow: 1;">
|
||||
<ui:Label tabindex="-1" text="加载一个Mod" parse-escape-sequences="true" display-tooltip-when-elided="true" name="mod-name-label" class="tl" />
|
||||
<ui:Label tabindex="-1" text="通过Windows Explorer选择Mod后,需要等待一段时间才能加载,这是因为explorer内部的延迟 可以直接加载编译好的dll 加载.cs需要安装MonoBleedingEdge 已加载的脚本mod无法动态完成卸载,可能需要重启应用 动态加载的Mod不会保存,如需要每次启动都自动加载,需要将Mod放置在/Mods/{ModName}/文件夹中,并创建PackageInfo.json描述文件" parse-escape-sequences="true" display-tooltip-when-elided="true" name="mod-description-label" style="white-space: normal;" />
|
||||
<ui:VisualElement style="flex-grow: 1;" />
|
||||
<ui:Button text="打开开发手册" parse-escape-sequences="true" display-tooltip-when-elided="true" name="open-manual-button" />
|
||||
<ui:Button text="打开Mod目录" parse-escape-sequences="true" display-tooltip-when-elided="true" name="open_folder-button" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TextCore.Text;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace BITKit.GameEditor
|
||||
{
|
||||
public class TMPFontCheck : EditorWindow
|
||||
{
|
||||
public static FontAsset CurrentFont;
|
||||
[MenuItem("Tools/TextMeshPro Font Check")]
|
||||
public static void ShowExample()
|
||||
{
|
||||
GetWindow<TMPFontCheck>().Show();
|
||||
}
|
||||
private void CreateGUI()
|
||||
{
|
||||
rootVisualElement.Clear();
|
||||
|
||||
var refreshButton = rootVisualElement.Create<Button>();
|
||||
refreshButton.text = "刷新";
|
||||
refreshButton.clicked += CreateGUI;
|
||||
|
||||
var mergeButton = rootVisualElement.Create<Button>();
|
||||
mergeButton.text = "合并字符串";
|
||||
|
||||
var fontField = rootVisualElement.Create<ObjectField>();
|
||||
fontField.objectType = typeof(FontAsset);
|
||||
|
||||
fontField.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
CurrentFont = x.newValue as FontAsset;
|
||||
});
|
||||
fontField.SetValueWithoutNotify(CurrentFont);
|
||||
|
||||
var container = rootVisualElement.Create<VisualElement>();
|
||||
container.style.flexDirection = FlexDirection.Column;
|
||||
|
||||
var label = container.Create<Label>();
|
||||
label.style.unityFontDefinition = new FontDefinition()
|
||||
{
|
||||
fontAsset = CurrentFont
|
||||
};
|
||||
|
||||
var textfield = container.Create<TextField>();
|
||||
textfield.label = "Test Font";
|
||||
textfield.multiline = true;
|
||||
|
||||
textfield.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
label.text = x.newValue;
|
||||
});
|
||||
|
||||
textfield.style.unityFontDefinition = label.style.unityFontDefinition;
|
||||
|
||||
mergeButton.clicked += () =>
|
||||
{
|
||||
textfield.value =new string(Regex.Replace(textfield.value, @"\s+", "").Distinct().ToArray());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 707aad4d7f4d82c46866eb25231c2388
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue