BITFALL/Assets/BITKit/Unity/Scripts/UX/DataBind/UXDataBindingService.cs

174 lines
4.6 KiB
C#
Raw Normal View History

2024-01-27 04:09:57 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
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)
{
var handler = new UXDataBindingHandler(ptr, value);
Handlers.Add(handler);
return handler;
}
public static unsafe UXDataBindingHandler CreateBinding(TypedReference typedReference)
{
UXDataBindingHandler handler = null;
var value = TypedReference.ToObject(typedReference);
switch (value)
{
case int:
{
ref var rawValue = ref __refvalue(typedReference, int);
handler = new UXDataBindingHandler(UnsafeUtility.AddressOf(ref rawValue), value);
}
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);
}
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;
}
[SerializeReference,SubclassSelector] private ITicker ticker;
[SerializeField,ReadOnly] private int bindingCount;
private void Start()
{
ticker.Add(OnTick);
destroyCancellationToken.Register(() => { ticker.Remove(OnTick); });
}
private void OnTick(float obj)
{
foreach (var handler in Handlers.ToArray())
{
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();
}
}
}
bindingCount = Handlers.Count;
}
}
}