1
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using BITKit.UX;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
@@ -11,163 +16,126 @@ using UnityEngine.UIElements;
|
||||
|
||||
namespace BITKit.IData
|
||||
{
|
||||
public sealed class UXDataBindingHandler:IDisposable
|
||||
{
|
||||
internal unsafe UXDataBindingHandler(void* ptr, object value)
|
||||
{
|
||||
ValueObject = ptr;
|
||||
SafeValueObject = value;
|
||||
|
||||
visualElement = value switch
|
||||
{
|
||||
Vector3 => new Vector3Field(),
|
||||
float => new FloatField(),
|
||||
int => new IntegerField(),
|
||||
_ => throw new InvalidCastException("未支持的数据类型"),
|
||||
};
|
||||
switch (visualElement)
|
||||
{
|
||||
case INotifyValueChanged<int> intField:
|
||||
intField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
//UnsafeUtility.AsRef<int>(ValueObject) = evt.newValue;
|
||||
//Unsafe.Write(ValueObject,evt.newValue);
|
||||
UnsafeUtility.AsRef<int>(ValueObject) = evt.newValue;
|
||||
});
|
||||
break;
|
||||
case INotifyValueChanged<float> floatField:
|
||||
floatField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
//Unsafe.Write(ValueObject,evt.newValue);
|
||||
UnsafeUtility.AsRef<float>(ValueObject) = evt.newValue;
|
||||
});
|
||||
break;
|
||||
case INotifyValueChanged<Vector3> vector3Field:
|
||||
vector3Field.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
//Unsafe.Write(ValueObject,evt.newValue);
|
||||
UnsafeUtility.AsRef<Vector3>(ValueObject) = evt.newValue;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
internal readonly unsafe void* ValueObject;
|
||||
internal object SafeValueObject;
|
||||
public VisualElement visualElement { get; }
|
||||
public void Dispose()
|
||||
{
|
||||
visualElement.RemoveFromHierarchy();
|
||||
}
|
||||
public unsafe void OnValueChanged()
|
||||
{
|
||||
SafeValueObject = SafeValueObject switch
|
||||
{
|
||||
int => UnsafeUtility.AsRef<int>(ValueObject),
|
||||
float => UnsafeUtility.AsRef<float>(ValueObject),
|
||||
Vector3 => UnsafeUtility.AsRef<Vector3>(ValueObject),
|
||||
_ => null
|
||||
};
|
||||
switch (visualElement)
|
||||
{
|
||||
case INotifyValueChanged<int> intField:
|
||||
intField.SetValueWithoutNotify((int)SafeValueObject);
|
||||
break;
|
||||
case INotifyValueChanged<float> floatField:
|
||||
floatField.SetValueWithoutNotify((float)SafeValueObject);
|
||||
break;
|
||||
case INotifyValueChanged<Vector3> vector3Field:
|
||||
vector3Field.SetValueWithoutNotify((Vector3)SafeValueObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UXDataBindingService : MonoBehaviour
|
||||
{
|
||||
private static readonly List<UXDataBindingHandler> Handlers = new();
|
||||
|
||||
public static unsafe UXDataBindingHandler CreateBinding(void* ptr, object value)
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
private static void Reload()
|
||||
{
|
||||
var handler = new UXDataBindingHandler(ptr, value);
|
||||
Handlers.Add(handler);
|
||||
return handler;
|
||||
_Binders.Clear();
|
||||
_Instances.Clear();
|
||||
}
|
||||
public static unsafe UXDataBindingHandler CreateBinding(TypedReference typedReference)
|
||||
private static readonly Dictionary<Type,IUXDataBinder> _Binders = new();
|
||||
private static readonly CacheList<IUXDataBinder> _Instances = new();
|
||||
|
||||
public static VisualElement Create(object target)
|
||||
{
|
||||
UXDataBindingHandler handler = null;
|
||||
var value = TypedReference.ToObject(typedReference);
|
||||
var visualElement = new VisualElement();
|
||||
var fields = target.GetType().GetFields(ReflectionHelper.Flags);
|
||||
foreach (var fieldInfo in fields.Where(x=>x.GetCustomAttribute<ExportAttribute>() is not null))
|
||||
{
|
||||
var handler = UXDataBindingService.Create(target,fieldInfo);
|
||||
var ui = handler.CreateUI(target, fieldInfo);
|
||||
visualElement.Add(ui);
|
||||
}
|
||||
|
||||
foreach (var methodInfo in target.GetType().GetMethods(ReflectionHelper.Flags))
|
||||
{
|
||||
if (Attribute.IsDefined(methodInfo, typeof(ExportAttribute)) is false) continue;
|
||||
var exportAttribute = methodInfo.GetCustomAttribute<ExportAttribute>();
|
||||
|
||||
var button = visualElement.Create<Button>();
|
||||
button.text =string.IsNullOrEmpty(exportAttribute.Name) ? methodInfo.Name:exportAttribute.Name;
|
||||
|
||||
button.clicked += OnClicked;
|
||||
|
||||
continue;
|
||||
void OnClicked()
|
||||
{
|
||||
try
|
||||
{
|
||||
methodInfo.Invoke(target, null);
|
||||
}
|
||||
catch (TargetInvocationException targetInvocationException)
|
||||
{
|
||||
if (targetInvocationException.InnerException is InGameException e is false) return;
|
||||
switch (e)
|
||||
{
|
||||
case {InnerException:not null}:
|
||||
Alert.Print(e.Message,e.InnerException.Message);
|
||||
break;
|
||||
default:
|
||||
Alert.Print(e.Message,e.Source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return visualElement;
|
||||
}
|
||||
|
||||
public static IUXDataBinder Create(object target,FieldInfo fieldInfo)
|
||||
{
|
||||
var value = fieldInfo.GetValue(target);
|
||||
var type = value?.GetType() ?? fieldInfo.FieldType;
|
||||
|
||||
// if (value is IEnumerable)
|
||||
// {
|
||||
// //type = typeof(IEnumerable<>).MakeGenericType(fieldInfo.FieldType.GetElementType());
|
||||
// //type = typeof(IEnumerable<>).MakeGenericType(type.GetGenericArguments());
|
||||
// }
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case int:
|
||||
{
|
||||
ref var rawValue = ref __refvalue(typedReference, int);
|
||||
handler = new UXDataBindingHandler(UnsafeUtility.AddressOf(ref rawValue), value);
|
||||
}
|
||||
case Array:
|
||||
type = typeof(IEnumerable<>).MakeGenericType(fieldInfo.FieldType.GetElementType());
|
||||
break;
|
||||
case float:
|
||||
{
|
||||
ref var rawValue = ref __refvalue(typedReference, float);
|
||||
handler = new UXDataBindingHandler(UnsafeUtility.AddressOf(ref rawValue), value);
|
||||
}
|
||||
break;
|
||||
case Vector3:
|
||||
{
|
||||
ref var rawValue = ref __refvalue(typedReference, Vector3);
|
||||
handler = new UXDataBindingHandler(UnsafeUtility.AddressOf(ref rawValue), value);
|
||||
}
|
||||
case IList:
|
||||
type = typeof(IEnumerable<>).MakeGenericType(type.GetGenericArguments());
|
||||
break;
|
||||
}
|
||||
|
||||
// var handler = (value) switch
|
||||
// {
|
||||
// case int=> new UXDataBindingHandler(UnsafeUtility.AddressOf(ref value), value),
|
||||
// _ => throw new InvalidCastException("未支持的数据类型"),
|
||||
// };
|
||||
|
||||
//var handler = new UXDataBindingHandler(&value, __refvalue(typedReference, object));
|
||||
Handlers.Add(handler);
|
||||
return handler;
|
||||
if (_Binders.TryGetValue(type, out var binder) is false)
|
||||
throw new NotImplementedException($"未支持的类型:{type.Name}");
|
||||
|
||||
var instance = (IUXDataBinder)Activator.CreateInstance(binder.GetType());
|
||||
_Instances.Add(instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
[SerializeReference, SubclassSelector] private ITicker ticker;
|
||||
|
||||
[SerializeReference,SubclassSelector] private ITicker ticker;
|
||||
|
||||
[SerializeField,ReadOnly] private int bindingCount;
|
||||
private void Start()
|
||||
private async void Start()
|
||||
{
|
||||
ticker.Add(OnTick);
|
||||
destroyCancellationToken.Register(() => { ticker.Remove(OnTick); });
|
||||
}
|
||||
|
||||
var binders = await ReflectionHelper.GetTypes<IUXDataBinder>();
|
||||
if(destroyCancellationToken.IsCancellationRequested)return;
|
||||
|
||||
private void OnTick(float obj)
|
||||
{
|
||||
foreach (var handler in Handlers.ToArray())
|
||||
foreach (var x in binders)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
if (handler.visualElement.parent is null)
|
||||
{
|
||||
Handlers.Remove(handler);
|
||||
continue;
|
||||
}
|
||||
|
||||
object value = handler.SafeValueObject switch
|
||||
{
|
||||
int => UnsafeUtility.AsRef<int>(handler.ValueObject),
|
||||
float => UnsafeUtility.AsRef<float>(handler.ValueObject),
|
||||
Vector3 => UnsafeUtility.AsRef<Vector3>(handler.ValueObject),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (value != handler.SafeValueObject)
|
||||
{
|
||||
handler.OnValueChanged();
|
||||
}
|
||||
}
|
||||
var instance = (IUXDataBinder)Activator.CreateInstance(x);
|
||||
if (_Binders.TryAdd(instance.TargetType, instance)) ;
|
||||
}
|
||||
|
||||
ticker.Add(OnTick);
|
||||
|
||||
destroyCancellationToken.Register(() =>
|
||||
{
|
||||
ticker.Remove(OnTick);
|
||||
});
|
||||
}
|
||||
private static void OnTick(float obj)
|
||||
{
|
||||
var array = _Instances.ValueArray;
|
||||
foreach (var x in array)
|
||||
{
|
||||
if (x.VisualElement.panel is null)
|
||||
{
|
||||
_Instances.Remove(x);
|
||||
continue;
|
||||
}
|
||||
x.OnTick(obj);
|
||||
}
|
||||
bindingCount = Handlers.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user