Compare commits

...

5 Commits

Author SHA1 Message Date
DCFApixels
d21c65742b Update package.json 2025-05-14 20:41:36 +08:00
DCFApixels
cb733e8903 Update RuntimeComponentsDrawer.cs 2025-05-14 20:31:01 +08:00
DCFApixels
64bc896457 Update RuntimeComponentsDrawer.cs 2025-05-14 20:26:17 +08:00
DCFApixels
6d0a572c80 refactoring RuntimeComponentsDrawer 2025-05-14 20:21:35 +08:00
DCFApixels
ed499de283 refactoring RuntimeComponentsDrawer 2025-05-14 20:19:40 +08:00
3 changed files with 351 additions and 293 deletions

View File

@ -8,7 +8,7 @@
"displayName": "DragonECS-Unity",
"description": "Integration with Unity for DragonECS",
"unity": "2021.2",
"version": "0.5.14",
"version": "0.5.14_1",
"repository": {
"type": "git",
"url": "https://github.com/DCFApixels/DragonECS-Unity.git"

View File

@ -15,7 +15,8 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
{
internal class RuntimeComponentsDrawer
{
private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private const BindingFlags INSTANCE_FIELD_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ResetRuntimeComponentReflectionCache()
{
@ -28,6 +29,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
}
private const int RuntimeComponentsMaxDepth = 2;
private const int RuntimeComponentsDepthRoot = -1;
private static RuntimeComponentsDrawer[] _drawers;
private static int _runtimeComponentsDepth = RuntimeComponentsDepthRoot;
static RuntimeComponentsDrawer()
@ -63,35 +65,11 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
internal class RuntimeComponentReflectionCache
{
public readonly Type Type;
public readonly bool IsUnityObjectType;
public readonly bool IsUnitySerializable;
public readonly bool IsCompositeType;
public readonly bool IsUnmanaged;
public readonly bool IsLeaf;
public readonly LeafType LeafPropertyType;
public enum LeafType
{
NONE = 0,
Enum,
Bool,
String,
Float,
Double,
Byte,
SByte,
Short,
UShort,
Int,
UInt,
Long,
ULong,
}
public readonly DrawerType DrawerType;
public readonly FieldInfoData[] Fields;
private RefEditorWrapper[] _wrappers = new RefEditorWrapper[2];
private RefEditorWrapper[] _wrappers = new RefEditorWrapper[RuntimeComponentsMaxDepth];
public RefEditorWrapper GetWrapper(int depth)
{
return _wrappers[depth];
@ -102,87 +80,88 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
Type = type;
ResetWrappers();
IsUnmanaged = UnsafeUtility.IsUnmanaged(type);
IsUnityObjectType = typeof(UnityObject).IsAssignableFrom(type);
LeafPropertyType = LeafType.NONE;
IsLeaf = type.IsPrimitive || type == typeof(string) || type.IsEnum;
bool isVoideType = type == typeof(void);
bool isUnityObjectType = typeof(UnityObject).IsAssignableFrom(type);
bool isLeaf = isUnityObjectType || type.IsPrimitive || type == typeof(string) || type.IsEnum;
if (IsLeaf)
DrawerType = DrawerType.UNDEFINED;
if(type.IsArray || isVoideType)
{
DrawerType = DrawerType.Ignored;
}
if (DrawerType == DrawerType.UNDEFINED && isLeaf)
{
if (type.IsEnum)
{
LeafPropertyType = LeafType.Enum;
DrawerType = type.HasAttribute<FlagsAttribute>() ? DrawerType.EnumFlags : DrawerType.Enum;
}
else if (isUnityObjectType)
{
DrawerType = DrawerType.UnityObject;
}
else if (type == typeof(bool))
{
LeafPropertyType = LeafType.Bool;
DrawerType = DrawerType.Bool;
}
else if (type == typeof(string))
{
LeafPropertyType = LeafType.String;
DrawerType = DrawerType.String;
}
else if (type == typeof(float))
{
LeafPropertyType = LeafType.Float;
DrawerType = DrawerType.Float;
}
else if (type == typeof(double))
{
LeafPropertyType = LeafType.Double;
DrawerType = DrawerType.Double;
}
else if (type == typeof(byte))
{
LeafPropertyType = LeafType.Byte;
DrawerType = DrawerType.Byte;
}
else if (type == typeof(sbyte))
{
LeafPropertyType = LeafType.SByte;
DrawerType = DrawerType.SByte;
}
else if (type == typeof(short))
{
LeafPropertyType = LeafType.Short;
DrawerType = DrawerType.Short;
}
else if (type == typeof(ushort))
{
LeafPropertyType = LeafType.UShort;
DrawerType = DrawerType.UShort;
}
else if (type == typeof(int))
{
LeafPropertyType = LeafType.Int;
DrawerType = DrawerType.Int;
}
else if (type == typeof(uint))
{
LeafPropertyType = LeafType.UInt;
DrawerType = DrawerType.UInt;
}
else if (type == typeof(long))
{
LeafPropertyType = LeafType.Long;
DrawerType = DrawerType.Long;
}
else if (type == typeof(ulong))
{
LeafPropertyType = LeafType.ULong;
DrawerType = DrawerType.ULong;
}
}
IsUnitySerializable =
IsUnityObjectType ||
//typeof(Array).IsAssignableFrom(type) ||
//(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) ||
//type.IsPrimitive ||
//type == typeof(string) ||
//type.IsEnum ||
(!type.IsGenericType && type.HasAttribute<System.SerializableAttribute>() && type.IsArray == false);
IsCompositeType =
type.IsPrimitive == false &&
type.IsArray == false &&
type != typeof(string);
if (type == typeof(void)) { return; }
if (IsUnitySerializable == false)
if (DrawerType == DrawerType.UNDEFINED)
{
var fieldInfos = type.GetFields(fieldFlags);
DrawerType = type.IsGenericType ? DrawerType.UnityNotSerializableComposite : DrawerType.UnitySerializableComposite;
}
if (isVoideType) { return; }
if (DrawerType == DrawerType.UnityNotSerializableComposite)
{
var fieldInfos = type.GetFields(INSTANCE_FIELD_FLAGS);
Fields = new FieldInfoData[fieldInfos.Length];
for (int i = 0; i < fieldInfos.Length; i++)
{
@ -204,6 +183,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
public readonly bool IsUnityObjectField;
public readonly bool IsPassToUnitySerialize;
public readonly RuntimeComponentReflectionCache ValueTypeReflectionCache;
public FieldInfoData(FieldInfo fieldInfo)
{
FieldInfo = fieldInfo;
@ -448,34 +428,73 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
#region draw data
private bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData, int depth)
{
const int DEPTH_MAX = 64;
const int DEPTH_MAX = 24;
using (EcsGUI.CheckChanged())
{
outData = data;
object newData = data;
Type type = data == null ? typeof(void) : data.GetType();
RuntimeComponentReflectionCache cache = fieldInfoData.GetReflectionCache(type);
bool isUnityObjectField = fieldInfoData.IsUnityObjectField;
if (isUnityObjectField == false && data == null)
{
EditorGUILayout.TextField(label, "Null");
return false;
}
RuntimeComponentReflectionCache cache = fieldInfoData.GetReflectionCache(type);
if (depth >= DEPTH_MAX || cache == null)
{
EditorGUILayout.TextField(label, "error");
return false;
}
bool isUnityObjectType = cache.IsUnityObjectType;
ref bool isExpanded = ref expandMatrix.Down();
bool changed = false;
bool childElementChanged = false;
var eventType = Event.current.type;
if (cache.IsUnitySerializable == false && cache.IsCompositeType)
var label2 = UnityEditorUtility.GetLabel2(cache.Type.FullName + " " + type.FullName);
var drawerType = cache.DrawerType;
if (isUnityObjectField)
{
drawerType = DrawerType.UnityObject;
}
switch (drawerType)
{
case DrawerType.UNDEFINED:
EditorGUILayout.LabelField(label, label2);
break;
case DrawerType.Ignored:
EditorGUILayout.LabelField(label, label2);
break;
case DrawerType.UnitySerializableComposite:
using (EcsGUI.CheckChanged())
{
RefEditorWrapper wrapper = cache.GetWrapper(_runtimeComponentsDepth);
wrapper.data = data;
wrapper.SO.Update();
wrapper.IsExpanded = isExpanded;
EditorGUILayout.PropertyField(wrapper.Property, label, true);
if (EcsGUI.Changed)
{
wrapper.SO.ApplyModifiedProperties();
newData = wrapper.Data;
childElementChanged = true;
}
isExpanded = wrapper.IsExpanded;
}
break;
case DrawerType.UnityNotSerializableComposite:
GUILayout.Space(EcsGUI.Spacing);
var foldoutStyle = EditorStyles.foldout;
Rect rect = GUILayoutUtility.GetRect(label, foldoutStyle);
rect.xMin += EcsGUI.Indent;
//rect.xMin += EcsGUI.Indent;
isExpanded = EditorGUI.BeginFoldoutHeaderGroup(rect, isExpanded, label, foldoutStyle, null, null);
EditorGUILayout.EndFoldoutHeaderGroup();
@ -489,184 +508,174 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData, depth + 1))
{
field.FieldInfo.SetValue(data, fieldData);
outData = data;
changed = true;
newData = data;
childElementChanged = true;
}
}
}
}
}
}
else
break;
case DrawerType.UnityObject:
using (EcsGUI.CheckChanged())
{
Type fieldType = fieldInfoData.FieldType;
if (isUnityObjectType || isUnityObjectField)
{
EditorGUI.BeginChangeCheck();
var uobj = UnsafeUtility.As<object, UnityObject>(ref data);
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldInfoData.FieldType);
var newuobj = EditorGUILayout.ObjectField(label, uobj, fieldInfoData.FieldType, true);
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldType);
if (isComponent)
if (uobj != newuobj)
{
uobj = EditorGUILayout.ObjectField(label, uobj, typeof(UnityObject), true);
if (isComponent && newuobj is GameObject go)
{
newuobj = go.GetComponent(fieldInfoData.FieldType);
}
newData = newuobj;
childElementChanged = true;
}
else
{
uobj = EditorGUILayout.ObjectField(label, uobj, fieldType, true);
}
if (EditorGUI.EndChangeCheck())
{
if (isComponent && uobj is GameObject go)
{
uobj = go.GetComponent(fieldType);
}
break;
case DrawerType.Enum:
outData = uobj;
changed = true;
}
}
else
{
EditorGUI.BeginChangeCheck();
RefEditorWrapper wrapper = cache.GetWrapper(_runtimeComponentsDepth);
wrapper.data = data;
try
{
if (fieldInfoData.IsPassToUnitySerialize)
{
if (cache.IsCompositeType)
{
wrapper.SO.Update();
wrapper.IsExpanded = isExpanded;
EditorGUILayout.PropertyField(wrapper.Property, label, true);
if (GUI.changed)
{
wrapper.SO.ApplyModifiedProperties();
}
}
else if (cache.IsLeaf)
{
var eventType = Event.current.type;
switch (cache.LeafPropertyType)
{
//case RuntimeComponentReflectionCache.LeafType.Enum:
// break;
case RuntimeComponentReflectionCache.LeafType.Bool:
if (eventType != EventType.Layout)
{
wrapper.data = EditorGUILayout.Toggle(label, (bool)data);
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumPopup(label, enumData);
}
else
{
EditorGUILayout.EnumPopup(label, default);
}
break;
case DrawerType.EnumFlags:
if (eventType != EventType.Layout)
{
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumFlagsField(label, enumData);
}
else
{
EditorGUILayout.EnumFlagsField(label, default);
}
break;
case DrawerType.Bool:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.Toggle(label, (bool)data);
}
else
{
EditorGUILayout.Toggle(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.String:
case DrawerType.String:
if (eventType != EventType.Layout)
{
wrapper.data = EditorGUILayout.TextField(label, (string)data);
newData = EditorGUILayout.TextField(label, (string)data);
}
else
{
EditorGUILayout.TextField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.Float:
case DrawerType.Float:
if (eventType != EventType.Layout)
{
wrapper.data = EditorGUILayout.FloatField(label, (float)data);
newData = EditorGUILayout.FloatField(label, (float)data);
}
else
{
EditorGUILayout.FloatField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.Double:
case DrawerType.Double:
if (eventType != EventType.Layout)
{
wrapper.data = EditorGUILayout.DoubleField(label, (double)data);
newData = EditorGUILayout.DoubleField(label, (double)data);
}
else
{
EditorGUILayout.DoubleField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.Byte:
case DrawerType.Byte:
if (eventType != EventType.Layout)
{
wrapper.data = (byte)EditorGUILayout.IntField(label, (byte)data);
newData = (byte)EditorGUILayout.IntField(label, (byte)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.SByte:
case DrawerType.SByte:
if (eventType != EventType.Layout)
{
wrapper.data = (sbyte)EditorGUILayout.IntField(label, (sbyte)data);
newData = (sbyte)EditorGUILayout.IntField(label, (sbyte)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.Short:
case DrawerType.Short:
if (eventType != EventType.Layout)
{
wrapper.data = (short)EditorGUILayout.IntField(label, (short)data);
newData = (short)EditorGUILayout.IntField(label, (short)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.UShort:
case DrawerType.UShort:
if (eventType != EventType.Layout)
{
wrapper.data = (ushort)EditorGUILayout.IntField(label, (ushort)data);
newData = (ushort)EditorGUILayout.IntField(label, (ushort)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.Int:
case DrawerType.Int:
if (eventType != EventType.Layout)
{
wrapper.data = (int)EditorGUILayout.IntField(label, (int)data);
newData = (int)EditorGUILayout.IntField(label, (int)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.UInt:
case DrawerType.UInt:
if (eventType != EventType.Layout)
{
wrapper.data = (uint)EditorGUILayout.IntField(label, (int)(uint)data);
newData = (uint)EditorGUILayout.IntField(label, (int)(uint)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.Long:
case DrawerType.Long:
if (eventType != EventType.Layout)
{
wrapper.data = EditorGUILayout.LongField(label, (long)data);
newData = EditorGUILayout.LongField(label, (long)data);
}
else
{
EditorGUILayout.LongField(label, default);
}
break;
case RuntimeComponentReflectionCache.LeafType.ULong:
case DrawerType.ULong:
if (eventType != EventType.Layout)
{
wrapper.data = (ulong)EditorGUILayout.LongField(label, (long)(ulong)data);
newData = (ulong)EditorGUILayout.LongField(label, (long)(ulong)data);
}
else
{
@ -674,40 +683,46 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
}
break;
default:
EditorGUILayout.LabelField(label);
EditorGUILayout.LabelField(label, label2);
break;
}
}
}
else
{
EditorGUILayout.LabelField(label);
}
}
catch (ArgumentException)
{
if (Event.current.type != EventType.Repaint)
{
throw;
}
}
finally
{
if (EditorGUI.EndChangeCheck())
{
outData = wrapper.Data;
changed = true;
}
isExpanded = wrapper.IsExpanded;
}
}
}
expandMatrix.Up();
return changed;
if (childElementChanged || EcsGUI.Changed)
{
outData = newData;
return true;
}
}
return false;
}
#endregion
public enum DrawerType
{
UNDEFINED = 0,
Ignored,
// Composite
UnitySerializableComposite,
UnityNotSerializableComposite,
// Leaft types
UnityObject,
Enum,
EnumFlags,
Bool,
String,
Float,
Double,
Byte,
SByte,
Short,
UShort,
Int,
UInt,
Long,
ULong,
}
}
}
#endif

View File

@ -235,6 +235,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
//private static Type[] _noHiddenSerializableTypes;
private static GUIContent _singletonIconContent = null;
private static GUIContent _singletonContent = null;
private static GUIContent _singleton2Content = null;
private static GUIStyle _inputFieldCenterAnhor = null;
private static Dictionary<Type, MonoScript> _scriptsAssets = new Dictionary<Type, MonoScript>(256);
@ -440,6 +441,17 @@ namespace DCFApixels.DragonECS.Unity.Editors
_singletonIconContent.tooltip = tooltip;
return _singletonIconContent;
}
public static GUIContent GetLabel2(string name, string tooltip = null)
{
if (_singleton2Content == null)
{
_singleton2Content = new GUIContent();
}
_singleton2Content.text = name;
_singleton2Content.image = null;
_singleton2Content.tooltip = tooltip;
return _singleton2Content;
}
#endregion
#region GetDefaultStyle
@ -517,6 +529,37 @@ namespace DCFApixels.DragonECS.Unity.Editors
return result;
}
#endregion
//private static StructList<GUIContent> _stackLabels = new StructList<GUIContent>(4);
//public static StackTempLabelScope GetStackLabel(string text, string tooltip = null)
//{
// StackTempLabelScope result = default;
// if (_stackLabels.Count <= 0)
// {
// result = new StackTempLabelScope(new GUIContent());
// }
// else
// {
// var l = _stackLabels[_stackLabels.Count - 1];
// _stackLabels.RemoveAt(_stackLabels.Count - 1);
// result = new StackTempLabelScope(l);
// }
// result.Label.text = text;
// result.Label.tooltip = tooltip;
// return result;
//}
//private static void ReturnStackLabel(GUIContent label)
//{
// _stackLabels.Add(label);
//}
//public readonly struct StackTempLabelScope : IDisposable
//{
// public readonly GUIContent Label;
// public StackTempLabelScope(GUIContent label) { Label = label; }
// public void Dispose() { ReturnStackLabel(Label); }
// public static implicit operator GUIContent(StackTempLabelScope a) { return a.Label; }
//}
}
internal static class RuntimeComponentsUtility