From 0c2e5c41bca1cc4b37ee4e8f4c32ef85b75458c1 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:11:16 +0800 Subject: [PATCH] update component templated drawing --- src/Internal/Editor/EcsGUI.cs | 42 ------- src/Internal/Editor/MetaObjectsDropDown.cs | 56 +++++---- src/Internal/Editor/UnityEditorUtility.cs | 3 +- src/Internal/Utils/PredicateTypesKey.cs | 72 +++++++++++ src/Internal/Utils/PredicateTypesKey.cs.meta | 11 ++ .../ComponentTemplateProperty.cs | 45 ++++--- .../Editor/ComponentTemplatePropertyDrawer.cs | 49 ++++++-- .../Editor/EntityTemplateEditor.cs | 5 +- .../Templates/ComponentTemplateBase.cs | 112 ++++++++++++++---- 9 files changed, 279 insertions(+), 116 deletions(-) create mode 100644 src/Internal/Utils/PredicateTypesKey.cs create mode 100644 src/Internal/Utils/PredicateTypesKey.cs.meta diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs index b93a1cc..c30bf2e 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -1005,48 +1005,6 @@ namespace DCFApixels.DragonECS.Unity.Editors } #endregion - #region PredicateTypesKey - private readonly struct PredicateTypesKey : IEquatable - { - public readonly Type[] types; - public readonly Type[] withoutTypes; - public PredicateTypesKey(Type[] types, Type[] withoutTypes) - { - this.types = types; - this.withoutTypes = withoutTypes; - } - public bool Equals(PredicateTypesKey other) - { - if (types.Length != other.types.Length) { return false; } - if (withoutTypes.Length != other.withoutTypes.Length) { return false; } - for (int i = 0; i < types.Length; i++) - { - if (types[i] != other.types[i]) - { - return false; - } - } - for (int i = 0; i < withoutTypes.Length; i++) - { - if (withoutTypes[i] != other.withoutTypes[i]) - { - return false; - } - } - return true; - } - public override bool Equals(object obj) - { - return obj is PredicateTypesKey key && Equals(key); - } - public override int GetHashCode() - { - return HashCode.Combine(types); - } - public static implicit operator PredicateTypesKey((Type[], Type[]) types) { return new PredicateTypesKey(types.Item1, types.Item2); } - } - #endregion - #region ReferenceDropDown private class ReferenceDropDown : AdvancedDropdown { diff --git a/src/Internal/Editor/MetaObjectsDropDown.cs b/src/Internal/Editor/MetaObjectsDropDown.cs index f8eb6a0..3f634eb 100644 --- a/src/Internal/Editor/MetaObjectsDropDown.cs +++ b/src/Internal/Editor/MetaObjectsDropDown.cs @@ -86,32 +86,37 @@ namespace DCFApixels.DragonECS.Unity.Editors } } } - internal class ComponentTemplatesDropDown : MetaObjectsDropDown + internal class ComponentTemplatesDropDown : MetaObjectsDropDown { - public ComponentTemplatesDropDown() - { - IEnumerable<(IComponentTemplate template, ITypeMeta meta)> itemMetaPairs = ComponentTemplateTypeCache.Dummies.ToArray().Select(dummy => - { - ITypeMeta meta; - if (dummy is ITypeMeta withMetaOverride) - { - meta = withMetaOverride; - } - else - { - meta = dummy.Type.GetMeta(); - } - return (dummy, meta); - }); - //TODO оптимизировать или вырезать - itemMetaPairs = itemMetaPairs.OrderBy(o => o.meta.Group.Name); - Setup(itemMetaPairs); - } + private ComponentTemplatesDropDown() { } private bool _isCheckUnique; private SerializedProperty _arrayProperty; private SerializedProperty _fieldProperty; + public static Dictionary _dropDownsCache = new Dictionary(32); + public static ComponentTemplatesDropDown Get(PredicateTypesKey key) + { + if(_dropDownsCache.TryGetValue(key, out var result) == false) + { + result = new ComponentTemplatesDropDown(); + IEnumerable<(ComponentTemplateTypeCache template, ITypeMeta meta)> itemMetaPairs = ComponentTemplateTypeCache.All.ToArray() + .Where(o => + { + return key.Check(o.Type); + }) + .Select(o => + { + return (o, o.Meta); + }); + //TODO оптимизировать или вырезать + itemMetaPairs = itemMetaPairs.OrderBy(o => o.meta.Group.Name); + result.Setup(itemMetaPairs); + _dropDownsCache[key] = result; + } + return result; + } + public void OpenForArray(Rect position, SerializedProperty arrayProperty, bool isCheckUnique) { _isCheckUnique = isCheckUnique; @@ -139,14 +144,14 @@ namespace DCFApixels.DragonECS.Unity.Editors } Type componentType = item.Obj.GetType(); - IComponentTemplate cmptmp = item.Obj; + var data = item.Obj; - if (_arrayProperty != null && cmptmp != null) + if (_arrayProperty != null && data != null) { int index = _arrayProperty.arraySize; if (_isCheckUnique) { - if (cmptmp.IsUnique) + if (data.IsUnique) { for (int i = 0, iMax = _arrayProperty.arraySize; i < iMax; i++) { @@ -163,7 +168,7 @@ namespace DCFApixels.DragonECS.Unity.Editors if (_fieldProperty != null) { - _fieldProperty.managedReferenceValue = cmptmp.Clone_Reflection(); + _fieldProperty.managedReferenceValue = data.CreateInstance(); _fieldProperty.serializedObject.ApplyModifiedProperties(); } } @@ -208,7 +213,8 @@ namespace DCFApixels.DragonECS.Unity.Editors { private string _name; private bool _isContainsNull; - private IEnumerable<(T, ITypeMeta)> _itemMetaPairs; + public IEnumerable<(T, ITypeMeta)> _itemMetaPairs; + public MetaObjectsDropDown() : base(new AdvancedDropdownState()) { minimumSize = new Vector2(220f, EditorGUIUtility.singleLineHeight * 20); diff --git a/src/Internal/Editor/UnityEditorUtility.cs b/src/Internal/Editor/UnityEditorUtility.cs index e3c005b..e293f33 100644 --- a/src/Internal/Editor/UnityEditorUtility.cs +++ b/src/Internal/Editor/UnityEditorUtility.cs @@ -142,7 +142,8 @@ namespace DCFApixels.DragonECS.Unity.Editors entityEditorBlockDrawers.Add(drawer); } - if (type.IsUnityObject() == false && type.GetConstructor(Type.EmptyTypes) != null) + if (type.IsUnityObject() == false && + (type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null)) { serializableTypes.Add(type); if (hasMetaID) diff --git a/src/Internal/Utils/PredicateTypesKey.cs b/src/Internal/Utils/PredicateTypesKey.cs new file mode 100644 index 0000000..a270ce1 --- /dev/null +++ b/src/Internal/Utils/PredicateTypesKey.cs @@ -0,0 +1,72 @@ +using System; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Internal +{ + internal readonly struct PredicateTypesKey : IEquatable + { + public readonly Type[] Types; + public readonly Type[] WithoutTypes; + public PredicateTypesKey(Type[] types) : this(types, Type.EmptyTypes) { } + public PredicateTypesKey(Type[] types, Type[] withoutTypes) + { + Types = types; + WithoutTypes = withoutTypes; + } + public bool Check(Type type) + { + bool isAssignable = false; + foreach (Type predicateTypes in Types) + { + if (predicateTypes.IsAssignableFrom(type)) + { + isAssignable = true; + break; + } + } + + if (isAssignable) + { + foreach (Type withoutType in WithoutTypes) + { + if (withoutType.IsAssignableFrom(type)) + { + isAssignable = false; + break; + } + } + } + + return isAssignable; + } + public bool Equals(PredicateTypesKey other) + { + if (Types.Length != other.Types.Length) { return false; } + if (WithoutTypes.Length != other.WithoutTypes.Length) { return false; } + for (int i = 0; i < Types.Length; i++) + { + if (Types[i] != other.Types[i]) + { + return false; + } + } + for (int i = 0; i < WithoutTypes.Length; i++) + { + if (WithoutTypes[i] != other.WithoutTypes[i]) + { + return false; + } + } + return true; + } + public override bool Equals(object obj) + { + return obj is PredicateTypesKey key && Equals(key); + } + public override int GetHashCode() + { + return HashCode.Combine(Types, WithoutTypes); + } + public static implicit operator PredicateTypesKey((Type[], Type[]) types) { return new PredicateTypesKey(types.Item1, types.Item2); } + } +} \ No newline at end of file diff --git a/src/Internal/Utils/PredicateTypesKey.cs.meta b/src/Internal/Utils/PredicateTypesKey.cs.meta new file mode 100644 index 0000000..41ca3b0 --- /dev/null +++ b/src/Internal/Utils/PredicateTypesKey.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ddc48a3a4dbc1c40a37a48e5adb86d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Templates/EntityTemplate/ComponentTemplateProperty.cs b/src/Templates/EntityTemplate/ComponentTemplateProperty.cs index 13129a3..514c461 100644 --- a/src/Templates/EntityTemplate/ComponentTemplateProperty.cs +++ b/src/Templates/EntityTemplate/ComponentTemplateProperty.cs @@ -12,13 +12,13 @@ namespace DCFApixels.DragonECS public struct ComponentTemplateProperty : IEquatable { [SerializeReference] - private IComponentTemplate _template; + private ITemplateNode _template; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ComponentTemplateProperty(IComponentTemplate template) + public ComponentTemplateProperty(ITemplateNode template) { _template = template; } - public IComponentTemplate Template + public ITemplateNode Template { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _template; } @@ -28,23 +28,41 @@ namespace DCFApixels.DragonECS public Type Type { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _template.Type; } + get { return _template is IComponentTemplate tml ? tml.Type : _template.GetType(); } } public bool IsNull { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _template == null; } } + private IComponentTemplate Tmpl + { + get { return _template as IComponentTemplate; } + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Apply(short worldID, int entityID) { _template.Apply(worldID, entityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public object GetRaw() { return _template.GetRaw(); } + public void OnGizmos(Transform transform, IComponentTemplate.GizmosMode mode) { Tmpl?.OnGizmos(transform, mode); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnGizmos(Transform transform, IComponentTemplate.GizmosMode mode) { _template.OnGizmos(transform, mode); } + public void OnValidate(UnityEngine.Object obj) { Tmpl?.OnValidate(obj); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnValidate(UnityEngine.Object obj) { _template.OnValidate(obj); } + public object GetRaw() + { + if(_template is IComponentTemplate tmpl) + { + return tmpl.GetRaw(); + } + return _template; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetRaw(object raw) { _template.SetRaw(raw); } + public void SetRaw(object raw) + { + if (_template is IComponentTemplate tmpl) + { + tmpl.SetRaw(raw); + } + _template = (IComponentTemplate)raw; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ComponentTemplateProperty other) { return _template == other._template; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -67,15 +85,10 @@ namespace DCFApixels.DragonECS public sealed class ComponentTemplateReferenceAttribute : PropertyAttribute, IReferenceButtonAttribute { - public readonly Type[] PredicateTypes; - public readonly bool IsHideButtonIfNotNull; + public Type[] PredicateTypes; Type[] IReferenceButtonAttribute.PredicateTypes { get { return PredicateTypes; } } - bool IReferenceButtonAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } } - public ComponentTemplateReferenceAttribute() - { - PredicateTypes = new Type[] { typeof(IComponentTemplate) }; - IsHideButtonIfNotNull = true; - } + bool IReferenceButtonAttribute.IsHideButtonIfNotNull { get { return true; } } + public ComponentTemplateReferenceAttribute() { } } public sealed class ComponentTemplateAttribute : PropertyAttribute { } } \ No newline at end of file diff --git a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs index 2cecfc6..1e5235e 100644 --- a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs +++ b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs @@ -9,7 +9,7 @@ namespace DCFApixels.DragonECS.Unity.Editors [CustomPropertyDrawer(typeof(ComponentTemplateProperty), true)] internal class ComponentTemplatePropertyDrawer : ExtendedPropertyDrawer { - private ComponentTemplateReferenceDrawer _drawer = new ComponentTemplateReferenceDrawer(); + private ComponentTemplateReferenceDrawer _drawer = new ComponentTemplateReferenceDrawer(new PredicateTypesKey(new Type[] { typeof(ITemplateNode) })); public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { property.Next(true); @@ -30,17 +30,48 @@ namespace DCFApixels.DragonECS.Unity.Editors internal class ComponentTemplateReferenceDrawer : ExtendedPropertyDrawer { private const float DamagedComponentHeight = 18f * 2f; - private static ComponentTemplatesDropDown _componentDropDown; + private ComponentTemplatesDropDown _componentDropDown; + private PredicateTypesKey? _predicateOverride; + #region Properties private float Padding => Spacing; - protected override bool IsStaticInit => _componentDropDown != null; + protected override bool IsInit => _componentDropDown != null; #endregion - #region Init - protected override void OnStaticInit() + public ComponentTemplateReferenceDrawer() { } + public ComponentTemplateReferenceDrawer(PredicateTypesKey key) { - _componentDropDown = new ComponentTemplatesDropDown(); + _predicateOverride = key; + } + + #region Init + protected override void OnInit() + { + PredicateTypesKey key; + if(_predicateOverride == null) + { + Type[] withOutTypes = Type.EmptyTypes; + if (fieldInfo != null) + { + withOutTypes = fieldInfo.TryGetAttribute(out ReferenceButtonWithOutAttribute a) ? a.PredicateTypes : Array.Empty(); + } + if (Attribute != null) + { + var types = Attribute.PredicateTypes; + if(types == null || types.Length == 0) + { + types = new Type[] { typeof(ITemplateNode) }; + } + key = new PredicateTypesKey(types, withOutTypes); + } + else + { + key = new PredicateTypesKey(new Type[] { typeof(object) }, withOutTypes); + } + _predicateOverride = key; + } + _componentDropDown = ComponentTemplatesDropDown.Get(_predicateOverride.Value); _componentDropDown.OnSelected += SelectComponent; } @@ -49,11 +80,11 @@ namespace DCFApixels.DragonECS.Unity.Editors private static void SelectComponent(ComponentTemplatesDropDown.Item item) { //EcsGUI.Changed = true; - currentProperty.managedReferenceValue = item.Obj.Clone_Reflection(); + object inst = item.Obj.CreateInstance(); + currentProperty.managedReferenceValue = inst; currentProperty.isExpanded = false; currentProperty.serializedObject.ApplyModifiedProperties(); } - #endregion public override float GetPropertyHeight(SerializedProperty property, GUIContent label) @@ -134,7 +165,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return; } - meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.GetMeta(); + meta = template is ITypeMeta metaOverride ? metaOverride : _predicateOverride.Value.Types[0].GetMeta(); } else { diff --git a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs index 5c98069..5c260db 100644 --- a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs +++ b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -1,6 +1,7 @@ #if UNITY_EDITOR using DCFApixels.DragonECS.Unity.Internal; using DCFApixels.DragonECS.Unity.RefRepairer.Editors; +using System; using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -15,13 +16,15 @@ namespace DCFApixels.DragonECS.Unity.Editors private ReorderableList _reorderableComponentsList; private int _reorderableComponentsListLastCount; + private static readonly Type[] _predicateTypes = new Type[] { typeof(ITemplateNode) }; + protected abstract bool IsSO { get; } #region Init protected override bool IsInit { get { return _componentDropDown != null; } } protected override void OnInit() { - _componentDropDown = new ComponentTemplatesDropDown(); + _componentDropDown = ComponentTemplatesDropDown.Get(new PredicateTypesKey(_predicateTypes, Type.EmptyTypes)); _componentsProp = serializedObject.FindProperty("_componentTemplates"); diff --git a/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs b/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs index ecdeefc..5f31235 100644 --- a/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs +++ b/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs @@ -1,10 +1,9 @@ #if DISABLE_DEBUG #undef DEBUG #endif +using DCFApixels.DragonECS.Unity.Internal; using System; -using System.Buffers; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using UnityEngine; @@ -142,34 +141,103 @@ namespace DCFApixels.DragonECS #if UNITY_EDITOR namespace DCFApixels.DragonECS.Unity.Editors { - internal static class ComponentTemplateTypeCache + internal class ComponentTemplateTypeCache { - private static Type[] _types; - private static IComponentTemplate[] _dummies; - internal static ReadOnlySpan Types + private static ComponentTemplateTypeCache[] _all; + internal static ReadOnlySpan All { - get { return _types; } - } - internal static ReadOnlySpan Dummies - { - get { return _dummies; } + get { return _all; } } static ComponentTemplateTypeCache() { - Type interfaceType = typeof(IComponentTemplate); - - _types = UnityEditorUtility._serializableTypes.Where(type => interfaceType.IsAssignableFrom(type)).ToArray(); - //foreach (var type in _types) - //{ - // EcsDebugUtility.GetTypeMeta(type); - //} - _dummies = new IComponentTemplate[_types.Length]; - - for (int i = 0; i < _types.Length; i++) + List list = new List(256); + foreach (var type in UnityEditorUtility._serializableTypes) { - _dummies[i] = (IComponentTemplate)Activator.CreateInstance(_types[i]); + //Debug.Log(type.Name); + if (typeof(ITemplateNode).IsAssignableFrom(type) && (typeof(IComponentTemplate).IsAssignableFrom(type) || typeof(IEcsComponentMember).IsAssignableFrom(type))) + { + ComponentTemplateTypeCache element = new ComponentTemplateTypeCache(type); + list.Add(element); + } } + _all = list.ToArray(); + } + + + public readonly Type Type; + public readonly Type ComponentType; + public readonly bool IsUnique; + private ITypeMeta _meta; + public ITypeMeta Meta + { + get + { + if (_meta == null) + { + _meta = ComponentType.GetMeta(); + } + return _meta; + } + } + private bool _defaultValueTypeInit = false; + private object _defaultValueDummy; + public object DefaultValue + { + get + { + if (_defaultValueTypeInit == false) + { + if (Type.IsValueType) + { + FieldInfo field; + field = Type.GetField("Default", BindingFlags.Static | BindingFlags.Public); + if (field != null && field.FieldType == Type) + { + _defaultValueDummy = field.GetValue(null); + } + + if(_defaultValueDummy == null) + { + field = Type.GetField("Empty", BindingFlags.Static | BindingFlags.Public); + if (field != null && field.FieldType == Type) + { + _defaultValueDummy = field.GetValue(null); + } + } + } + _defaultValueTypeInit = true; + } + return _defaultValueDummy; + } + } + public ComponentTemplateTypeCache(Type type) + { + Type = type; + + IsUnique = false; + if (typeof(IComponentTemplate).IsAssignableFrom(type)) + { + var ct = (IComponentTemplate)Activator.CreateInstance(type); + IsUnique = ct.IsUnique; + ComponentType = ct.Type; + if (ct is ITypeMeta metaOverride) + { + _meta = metaOverride; + } + } + else + { + ComponentType = Type; + } + } + public object CreateInstance() + { + if(DefaultValue != null) + { + return DefaultValue.Clone_Reflection(); + } + return Activator.CreateInstance(Type); } } }