diff --git a/src/Buildin/UnityComponent.cs b/src/Buildin/UnityComponent.cs index 7a414a5..d55114c 100644 --- a/src/Buildin/UnityComponent.cs +++ b/src/Buildin/UnityComponent.cs @@ -45,16 +45,9 @@ namespace DCFApixels.DragonECS [MetaGroup(EcsUnityConsts.PACK_GROUP, OTHER_GROUP)] [MetaDescription(AUTHOR, "Template for UnityComponent")] [MetaID("DragonECS_13DAACF9910155DD27F822442987E0AE")] + [MetaProxy(typeof(UnityComponentTemplate<>.UnityComponentMetaProxy))] public abstract class UnityComponentTemplate : ComponentTemplateBase> where T : Component { - public override string Name - { - get { return typeof(T).Name; } - } - public override MetaGroup Group - { - get { return UnityComponentConsts.BaseGroup; } - } public sealed override void Apply(short worldID, int entityID) { EcsWorld.GetPoolInstance>>(worldID).TryAddOrGet(entityID) = component; @@ -69,5 +62,11 @@ namespace DCFApixels.DragonECS } } } + protected class UnityComponentMetaProxy : ComponentTemplateMetaProxy + { + public override string Name { get { return typeof(T).GetMeta().Name; } } + public override MetaGroup Group { get { return UnityComponentConsts.BaseGroup; } } + public UnityComponentMetaProxy(Type type) : base(type) { } + } } } \ No newline at end of file diff --git a/src/DebugUtils/Editor/EntlongDrawer.cs b/src/DebugUtils/Editor/EntlongDrawer.cs index 6d5c95b..c178b96 100644 --- a/src/DebugUtils/Editor/EntlongDrawer.cs +++ b/src/DebugUtils/Editor/EntlongDrawer.cs @@ -186,7 +186,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return false; } - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + protected override float GetCustomHeight(SerializedProperty property, GUIContent label) { const float UNITY_HEIGHT_CONSTANT = 18f; if (property.hasMultipleDifferentValues) diff --git a/src/DebugUtils/Monitors/Editor/WorldQueriesMonitorEditor.cs b/src/DebugUtils/Monitors/Editor/WorldQueriesMonitorEditor.cs index 4172f96..bafc311 100644 --- a/src/DebugUtils/Monitors/Editor/WorldQueriesMonitorEditor.cs +++ b/src/DebugUtils/Monitors/Editor/WorldQueriesMonitorEditor.cs @@ -12,6 +12,74 @@ namespace DCFApixels.DragonECS.Unity.Editors internal class WorldQueriesMonitorEditor : ExtendedEditor { private GUIStyle _headerStyle; + private const char _searchPatternSeparator = '/'; + + public readonly struct SearchPattern + { + private readonly string _pattern; + private readonly char _separator; + public SearchPattern(string pattern, char separator) + { + _pattern = pattern ?? throw new ArgumentNullException(nameof(pattern)); + _separator = separator; + } + public Enumerator GetEnumerator() => new Enumerator(_pattern, _separator); + public ref struct Enumerator + { + private readonly string _pattern; + private readonly char _separator; + private int _start; + private int _currentStart; + private int _currentLength; + + public Enumerator(string pattern, char separator) + { + _pattern = pattern; + _separator = separator; + _start = 0; + _currentStart = -1; + _currentLength = 0; + } + + public ReadOnlySpan Current + { + get + { + if (_currentStart < 0) + throw new InvalidOperationException("Enumeration not started or already finished"); + return _pattern.AsSpan(_currentStart, _currentLength); + } + } + + public bool MoveNext() + { + if (_pattern == null || _start > _pattern.Length) + return false; + + int len = _pattern.Length; + while (_start <= len) + { + int i = _start; + while (i < len && _pattern[i] != _separator) + i++; + + int subLen = i - _start; + if (subLen > 0) // возвращаем только непустые подстроки + { + _currentStart = _start; + _currentLength = subLen; + _start = i + 1; + return true; + } + + // пустая подстрока — пропускаем разделитель и продолжаем + _start = i + 1; + } + + return false; + } + } + } private void CopyToClipboard() { @@ -148,21 +216,42 @@ namespace DCFApixels.DragonECS.Unity.Editors int i = 0; foreach (var executor in executors) { - bool cheack(ReadOnlySpan types, string searchPattern) + bool cheack(ReadOnlySpan types, ReadOnlySpan searchPatternRaw) { foreach (var type in types) { - if(type.Name.Contains(searchPattern, StringComparison.OrdinalIgnoreCase)) + if(type.Name.AsSpan().Contains(searchPatternRaw, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } - if (!HasSearchPattern || - cheack(executor.Mask.GetIncTypes_Debug(), searchPattern) || - cheack(executor.Mask.GetExcTypes_Debug(), searchPattern) || - cheack(executor.Mask.GetAnyTypes_Debug(), searchPattern)) + + bool isDraw = false; + if (HasSearchPattern) + { + int subPuttornsCount = 0; + int checkPassesCount = 0; + foreach (var subPattern in new SearchPattern(searchPattern, _searchPatternSeparator)) + { + subPuttornsCount++; + if (cheack(executor.Mask.GetIncTypes_Debug(), subPattern) || + cheack(executor.Mask.GetExcTypes_Debug(), subPattern) || + cheack(executor.Mask.GetAnyTypes_Debug(), subPattern)) + { + checkPassesCount++; + } + } + isDraw = subPuttornsCount <= checkPassesCount; + } + else + { + isDraw = true; + } + + + if(isDraw) { DrawQueryInfo(executor, i++); } diff --git a/src/Internal/AddParamsDrawer.cs b/src/Internal/AddParamsDrawer.cs index 38eb2d6..3763124 100644 --- a/src/Internal/AddParamsDrawer.cs +++ b/src/Internal/AddParamsDrawer.cs @@ -29,8 +29,7 @@ namespace DCFApixels.DragonECS.Unity.Editors { (byte)AddParamsFlags.NoImport | 7, "NoImport, Layer, Order, IsUnique" }, { byte.MaxValue, "NoImport, Layer, Order, IsUnique" }, }; - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + protected override float GetCustomHeight(SerializedProperty property, GUIContent label) { //return !property.isExpanded ? // EditorGUIUtility.singleLineHeight + Spacing : diff --git a/src/Internal/CustomToggleAttribute.cs b/src/Internal/CustomToggleAttribute.cs index 1bda942..468904d 100644 --- a/src/Internal/CustomToggleAttribute.cs +++ b/src/Internal/CustomToggleAttribute.cs @@ -18,6 +18,10 @@ namespace DCFApixels.DragonECS.Unity.Editors [CustomPropertyDrawer(typeof(CustomToggleAttribute))] internal class LeftToggleAttributeDrawer : ExtendedPropertyDrawer { + protected override float GetCustomHeight(SerializedProperty property, GUIContent label) + { + return OneLineHeight + Spacing; + } protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) { if (property.propertyType != SerializedPropertyType.Boolean) diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs index c30bf2e..48fb4e6 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -426,8 +426,8 @@ namespace DCFApixels.DragonECS.Unity.Editors using (SetAlpha(0)) { bool result = GUI.Button(position, string.Empty, EditorStyles.miniButtonMid); - var current = Event.current; - return (GUI.enabled && HitTest(position, current), result); + var currentEvent = Event.current; + return (GUI.enabled && HitTest(position, currentEvent), result); } } public static bool IconHoverScan(Rect position, Event current) @@ -486,11 +486,13 @@ namespace DCFApixels.DragonECS.Unity.Editors if (current.type == EventType.MouseUp) { EditorGUIUtility.PingObject(script); + Event.current.Use(); } else if (current.type == EventType.MouseDown && current.clickCount >= 2) { //UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(); //TODO AssetDatabase.OpenAsset(script); + Event.current.Use(); } } } @@ -715,23 +717,23 @@ namespace DCFApixels.DragonECS.Unity.Editors return DrawTypeMetaBlockPadding * 2 + contentHeight; } - public static bool DrawTypeMetaElementBlock(ref Rect rect, SerializedProperty arrayProperty, int elementIndex, SerializedProperty elementRootProperty, ITypeMeta meta) + public static (bool skip, float optionsWidth) DrawTypeMetaElementBlock(ref Rect rect, SerializedProperty arrayProperty, int elementIndex, SerializedProperty elementRootProperty, ITypeMeta meta) { var result = DrawTypeMetaBlock_Internal(ref rect, elementRootProperty, meta, elementIndex, arrayProperty.arraySize); - if (result.HasFlag(DrawTypeMetaBlockResultFlags.CloseButtonClicked)) + if (result.flags.HasFlag(DrawTypeMetaBlockResultFlags.CloseButtonClicked)) { arrayProperty.DeleteArrayElementAtIndex(elementIndex); } - return result != DrawTypeMetaBlockResultFlags.None; + return (result.flags != DrawTypeMetaBlockResultFlags.None, result.optionsWidth); } - public static bool DrawTypeMetaBlock(ref Rect rect, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1) + public static (bool skip, float optionsWidth) DrawTypeMetaBlock(ref Rect rect, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1) { var result = DrawTypeMetaBlock_Internal(ref rect, rootProperty, meta, index, total); - if (result.HasFlag(DrawTypeMetaBlockResultFlags.CloseButtonClicked)) + if (result.flags.HasFlag(DrawTypeMetaBlockResultFlags.CloseButtonClicked)) { rootProperty.ResetValues(); } - return result.HasFlag(DrawTypeMetaBlockResultFlags.DropExpanded); + return (result.flags.HasFlag(DrawTypeMetaBlockResultFlags.DropExpanded), result.optionsWidth); } [Flags] @@ -743,12 +745,12 @@ namespace DCFApixels.DragonECS.Unity.Editors } - private static DrawTypeMetaBlockResultFlags DrawTypeMetaBlock_Internal(ref Rect rect, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1) + private static (DrawTypeMetaBlockResultFlags flags, float optionsWidth) DrawTypeMetaBlock_Internal(ref Rect rect, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1) { if (meta == null) { EditorGUI.DrawRect(rect, Color.black.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA)); - return DrawTypeMetaBlockResultFlags.None; + return (DrawTypeMetaBlockResultFlags.None, 0f); } //string name = meta.Name; @@ -772,6 +774,7 @@ namespace DCFApixels.DragonECS.Unity.Editors EditorGUI.DrawRect(rect, panelColor); + float optionsWidth = 0f; Rect optionRect = rect; rect = rect.AddPadding(DrawTypeMetaBlockPadding * 2f); @@ -781,38 +784,45 @@ namespace DCFApixels.DragonECS.Unity.Editors optionRect.xMin = optionRect.xMax - 64; optionRect.center += Vector2.up * DrawTypeMetaBlockPadding; + DrawTypeMetaBlockResultFlags result = DrawTypeMetaBlockResultFlags.None; using (CheckChanged()) { //Canceling isExpanded - bool oldIsExpanded = rootProperty.isExpanded; - if (ClickTest(optionRect)) - { - rootProperty.isExpanded = oldIsExpanded; - result |= DrawTypeMetaBlockResultFlags.DropExpanded; - } + //bool oldIsExpanded = rootProperty.isExpanded; + //if (ClickTest(optionRect)) + //{ + // rootProperty.isExpanded = oldIsExpanded; + // result |= DrawTypeMetaBlockResultFlags.DropExpanded; + //} //Close button optionRect.xMin = optionRect.xMax - HeadIconsRect.width; + optionsWidth += optionRect.width; + if (CloseButton(optionRect)) { result |= DrawTypeMetaBlockResultFlags.CloseButtonClicked; - return result; + return (result, optionsWidth); } //Edit script button if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script)) { optionRect = HeadIconsRect.MoveTo(optionRect.center - (Vector2.right * optionRect.width)); + optionsWidth += optionRect.width; + ScriptAssetButton(optionRect, script); } //Description icon if (string.IsNullOrEmpty(description) == false) { optionRect = HeadIconsRect.MoveTo(optionRect.center - (Vector2.right * optionRect.width)); + optionsWidth += optionRect.width; + DescriptionIcon(optionRect, description); } } - return result; + return (result, optionsWidth); } #endregion @@ -978,11 +988,11 @@ namespace DCFApixels.DragonECS.Unity.Editors #region Init private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes, Type[] sortedWithOutTypes) { - if (_predicatTypesMenus.TryGetValue((predicatTypes, sortedWithOutTypes), out ReferenceDropDown menu) == false) + if (_predicatTypesMenus.TryGetValue(new PredicateTypesKey(predicatTypes[0], predicatTypes, sortedWithOutTypes), out ReferenceDropDown menu) == false) { menu = new ReferenceDropDown(predicatTypes, sortedWithOutTypes); menu.OnSelected += SelectComponent; - _predicatTypesMenus.Add((predicatTypes, sortedWithOutTypes), menu); + _predicatTypesMenus.Add(new PredicateTypesKey(predicatTypes[0], predicatTypes, sortedWithOutTypes), menu); } return menu; diff --git a/src/Internal/Editor/ExtendedEditor.cs b/src/Internal/Editor/ExtendedEditor.cs index d4f267d..720e7d6 100644 --- a/src/Internal/Editor/ExtendedEditor.cs +++ b/src/Internal/Editor/ExtendedEditor.cs @@ -17,6 +17,7 @@ namespace DCFApixels.DragonECS.Unity.Editors using System.Reflection; using UnityEditor; using UnityEngine; + using UnityEngine.UIElements; using UnityObject = UnityEngine.Object; @@ -213,21 +214,30 @@ namespace DCFApixels.DragonECS.Unity.Editors _isStaticInit = true; OnStaticInit(); } - public void Init() + public void Init(SerializedProperty property) { if (IsInit) { return; } _isInit = true; - OnInit(); + OnInit(property); } protected virtual void OnStaticInit() { } - protected virtual void OnInit() { } + protected virtual void OnInit(SerializedProperty property) { } + + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + StaticInit(); + Init(property); + return GetCustomHeight(property, label); + } + protected abstract float GetCustomHeight(SerializedProperty property, GUIContent label); public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { using (EcsGUI.CheckChanged(property.serializedObject)) { StaticInit(); - Init(); + Init(property); DrawCustom(position, property, label); } } diff --git a/src/Internal/Editor/MetaObjectsDropDown.cs b/src/Internal/Editor/MetaObjectsDropDown.cs index 3f634eb..fa03f55 100644 --- a/src/Internal/Editor/MetaObjectsDropDown.cs +++ b/src/Internal/Editor/MetaObjectsDropDown.cs @@ -86,93 +86,94 @@ namespace DCFApixels.DragonECS.Unity.Editors } } } - internal class ComponentTemplatesDropDown : MetaObjectsDropDown - { - 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; - _arrayProperty = arrayProperty; - _fieldProperty = null; - Show(position); - } - public void OpenForField(Rect position, SerializedProperty fieldProperty) - { - _isCheckUnique = false; - _arrayProperty = null; - _fieldProperty = fieldProperty; - Show(position); - } - - protected override void ItemSelected(Item item) - { - base.ItemSelected(item); - - if (item.Obj == null) - { - _fieldProperty.managedReferenceValue = null; - _fieldProperty.serializedObject.ApplyModifiedProperties(); - return; - } - - Type componentType = item.Obj.GetType(); - var data = item.Obj; - - if (_arrayProperty != null && data != null) - { - int index = _arrayProperty.arraySize; - if (_isCheckUnique) - { - if (data.IsUnique) - { - for (int i = 0, iMax = _arrayProperty.arraySize; i < iMax; i++) - { - if (_arrayProperty.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType) - { - return; - } - } - } - } - _arrayProperty.arraySize += 1; - _fieldProperty = _arrayProperty.GetArrayElementAtIndex(index); - } - - if (_fieldProperty != null) - { - _fieldProperty.managedReferenceValue = data.CreateInstance(); - _fieldProperty.serializedObject.ApplyModifiedProperties(); - } - } - } + //internal class ComponentTemplatesDropDown : MetaObjectsDropDown + //{ + // 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; + // _arrayProperty = arrayProperty; + // _fieldProperty = null; + // Show(position); + // } + // public void OpenForField(Rect position, SerializedProperty fieldProperty) + // { + // _isCheckUnique = false; + // _arrayProperty = null; + // _fieldProperty = fieldProperty; + // Show(position); + // } + // + // protected override void ItemSelected(Item item) + // { + // base.ItemSelected(item); + // + // if (item.Obj == null) + // { + // _fieldProperty.managedReferenceValue = null; + // _fieldProperty.serializedObject.ApplyModifiedProperties(); + // return; + // } + // + // Type componentType = item.Obj.GetType(); + // var data = item.Obj; + // + // if (_arrayProperty != null && data != null) + // { + // int index = _arrayProperty.arraySize; + // if (_isCheckUnique) + // { + // if (data.IsUnique) + // { + // for (int i = 0, iMax = _arrayProperty.arraySize; i < iMax; i++) + // { + // if (_arrayProperty.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType) + // { + // return; + // } + // } + // } + // } + // _arrayProperty.arraySize += 1; + // _fieldProperty = _arrayProperty.GetArrayElementAtIndex(index); + // } + // + // if (_fieldProperty != null) + // { + // _fieldProperty.managedReferenceValue = data.CreateInstance(); + // _fieldProperty.serializedObject.ApplyModifiedProperties(); + // } + // } + //} internal class RuntimeComponentsDropDown : MetaObjectsDropDown { public RuntimeComponentsDropDown(IEnumerable pools) @@ -215,6 +216,7 @@ namespace DCFApixels.DragonECS.Unity.Editors private bool _isContainsNull; public IEnumerable<(T, ITypeMeta)> _itemMetaPairs; + public virtual bool IsStaticList { get { return true; } } public MetaObjectsDropDown() : base(new AdvancedDropdownState()) { minimumSize = new Vector2(220f, EditorGUIUtility.singleLineHeight * 20); @@ -225,6 +227,10 @@ namespace DCFApixels.DragonECS.Unity.Editors _name = name; _isContainsNull = isContainsNull; _itemMetaPairs = itemMetaPairs; + if (IsStaticList) + { + _itemMetaPairs = _itemMetaPairs.ToArray(); + } } protected override AdvancedDropdownItem BuildRoot() { @@ -235,10 +241,9 @@ namespace DCFApixels.DragonECS.Unity.Editors { root.AddChild(new Item(default, "", increment++)); } - Dictionary dict = new Dictionary(); - + var list = _itemMetaPairs.ToArray(); foreach (var pair in _itemMetaPairs) { ITypeMeta meta = pair.Item2; diff --git a/src/Internal/ReferenceButtonAttributeDrawer.cs b/src/Internal/ReferenceButtonAttributeDrawer.cs index 2a3b5de..a28b21c 100644 --- a/src/Internal/ReferenceButtonAttributeDrawer.cs +++ b/src/Internal/ReferenceButtonAttributeDrawer.cs @@ -1,117 +1,109 @@ -using System; - -namespace DCFApixels.DragonECS.Unity.Editors -{ - internal interface IReferenceButtonAttribute - { - Type[] PredicateTypes { get; } - bool IsHideButtonIfNotNull { get; } - } -} - -#if UNITY_EDITOR -namespace DCFApixels.DragonECS.Unity.Internal -{ - using DCFApixels.DragonECS.Unity.Editors; - using UnityEditor; - internal partial class UnityReflectionCache - { - public bool IsReferenceButtonCacheInit_Editor; - public bool InitReferenceButtonCache_Editor(SerializedProperty sp) - { - if (IsReferenceButtonCacheInit_Editor) { return false; } - - HasSerializableData_Editor = sp.HasSerializableData(); - - IsReferenceButtonCacheInit_Editor = true; - return true; - } - public bool HasSerializableData_Editor; - } -} - -namespace DCFApixels.DragonECS.Unity.Editors -{ - using DCFApixels.DragonECS.Unity.Internal; - using System; - using UnityEditor; - using UnityEngine; - - [CustomPropertyDrawer(typeof(ReferenceButtonAttribute), true)] - internal sealed class ReferenceButtonAttributeDrawer : ExtendedPropertyDrawer - { - private Type[] _withOutTypes; - protected override void OnInit() - { - Type fieldType = fieldInfo.FieldType; - _withOutTypes = fieldType.TryGetAttribute(out ReferenceButtonWithOutAttribute a) ? a.PredicateTypes : Array.Empty(); - //if (fieldType.IsGenericType) - //{ - // if (fieldType.IsGenericTypeDefinition == false) - // { - // fieldType = fieldType.GetGenericTypeDefinition(); - // } - //} - } - - private UnityReflectionCache _reflectionCache; - private UnityReflectionCache Cahce(SerializedProperty sp) - { - if (UnityReflectionCache.InitLocal(sp.managedReferenceValue.GetType(), ref _reflectionCache)) - { - _reflectionCache.InitReferenceButtonCache_Editor(sp); - } - return _reflectionCache; - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - Init(); - if (property.propertyType == SerializedPropertyType.ManagedReference && - property.managedReferenceValue != null && - Cahce(property).HasSerializableData_Editor) - { - return EditorGUI.GetPropertyHeight(property, label, true); - } - else - { - return OneLineHeight; - } - } - - protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) - { - if(property.propertyType != SerializedPropertyType.ManagedReference) - { - GUI.Label(position, label); - return; - } - if (IsArrayElement) - { - label = UnityEditorUtility.GetLabelTemp(); - } - Rect selButtnoRect = position; - selButtnoRect.height = OneLineHeight; - DrawSelectionPopupButton(selButtnoRect, property); - - if (property.managedReferenceValue != null && - Cahce(property).HasSerializableData_Editor) - { - EditorGUI.PropertyField(position, property, label, true); - } - else - { - EditorGUI.BeginProperty(position, label, property); - EditorGUI.LabelField(position, label); - EditorGUI.EndProperty(); - } - } - - private void DrawSelectionPopupButton(Rect position, SerializedProperty property) - { - Rect buttonRect = IsArrayElement ? position : position.AddPadding(EditorGUIUtility.labelWidth, 0f, 0f, 0f); ; - EcsGUI.DrawSelectReferenceButton(buttonRect, property, Attribute.PredicateTypes.Length == 0 ? new Type[1] { fieldInfo.FieldType } : Attribute.PredicateTypes, _withOutTypes, Attribute.IsHideButtonIfNotNull); - } - } -} -#endif \ No newline at end of file +//using System; +// +//#if UNITY_EDITOR +//namespace DCFApixels.DragonECS.Unity.Internal +//{ +// using DCFApixels.DragonECS.Unity.Editors; +// using UnityEditor; +// internal partial class UnityReflectionCache +// { +// public bool IsReferenceButtonCacheInit_Editor; +// public bool InitReferenceButtonCache_Editor(SerializedProperty sp) +// { +// if (IsReferenceButtonCacheInit_Editor) { return false; } +// +// HasSerializableData_Editor = sp.HasSerializableData(); +// +// IsReferenceButtonCacheInit_Editor = true; +// return true; +// } +// public bool HasSerializableData_Editor; +// } +//} +// +//namespace DCFApixels.DragonECS.Unity.Editors +//{ +// using DCFApixels.DragonECS.Unity.Internal; +// using System; +// using UnityEditor; +// using UnityEngine; +// +// [CustomPropertyDrawer(typeof(ReferenceButtonAttribute), true)] +// internal sealed class ReferenceButtonAttributeDrawer : ExtendedPropertyDrawer +// { +// private Type[] _withOutTypes; +// +// protected override void OnInit(SerializedProperty property) +// { +// Type fieldType = fieldInfo.FieldType; +// _withOutTypes = fieldType.TryGetAttribute(out ReferenceButtonWithOutAttribute a) ? a.PredicateTypes : Array.Empty(); +// //if (fieldType.IsGenericType) +// //{ +// // if (fieldType.IsGenericTypeDefinition == false) +// // { +// // fieldType = fieldType.GetGenericTypeDefinition(); +// // } +// //} +// } +// +// private UnityReflectionCache _reflectionCache; +// private UnityReflectionCache Cahce(SerializedProperty sp) +// { +// if (UnityReflectionCache.InitLocal(sp.managedReferenceValue.GetType(), ref _reflectionCache)) +// { +// _reflectionCache.InitReferenceButtonCache_Editor(sp); +// } +// return _reflectionCache; +// } +// +// public override float GetPropertyHeight(SerializedProperty property, GUIContent label) +// { +// Init(property); +// if (property.propertyType == SerializedPropertyType.ManagedReference && +// property.managedReferenceValue != null && +// Cahce(property).HasSerializableData_Editor) +// { +// return EditorGUI.GetPropertyHeight(property, label, true); +// } +// else +// { +// return OneLineHeight; +// } +// } +// +// protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) +// { +// if(property.propertyType != SerializedPropertyType.ManagedReference) +// { +// GUI.Label(position, label); +// return; +// } +// if (IsArrayElement) +// { +// label = UnityEditorUtility.GetLabelTemp(); +// } +// Rect selButtnoRect = position; +// selButtnoRect.height = OneLineHeight; +// DrawSelectionPopupButton(selButtnoRect, property); +// +// if (property.managedReferenceValue != null && +// Cahce(property).HasSerializableData_Editor) +// { +// EditorGUI.PropertyField(position, property, label, true); +// } +// else +// { +// EditorGUI.BeginProperty(position, label, property); +// EditorGUI.LabelField(position, label); +// EditorGUI.EndProperty(); +// } +// } +// +// private void DrawSelectionPopupButton(Rect position, SerializedProperty property) +// { +// Rect buttonRect = IsArrayElement ? position : position.AddPadding(EditorGUIUtility.labelWidth, 0f, 0f, 0f); ; +// EcsGUI.DrawSelectReferenceButton(buttonRect, property, Attribute.PredicateTypes.Length == 0 ? new Type[1] { fieldInfo.FieldType } : Attribute.PredicateTypes, _withOutTypes, Attribute.IsHideButtonIfNotNull); +// } +// } +//} +//#endif \ No newline at end of file diff --git a/src/Internal/ReflectionExtensions.cs b/src/Internal/ReflectionExtensions.cs index cffa79e..eee6a00 100644 --- a/src/Internal/ReflectionExtensions.cs +++ b/src/Internal/ReflectionExtensions.cs @@ -105,10 +105,6 @@ namespace DCFApixels.DragonECS.Unity.Internal } return _memberwiseCloneMethdo.Invoke(obj, null); } - internal static object Clone_Reflection(this T obj) - { - return Clone_Reflection((object)obj); - } } internal partial class UnityReflectionCache diff --git a/src/Internal/Utils/PredicateTypesKey.cs b/src/Internal/Utils/PredicateTypesKey.cs index a270ce1..9ab53c3 100644 --- a/src/Internal/Utils/PredicateTypesKey.cs +++ b/src/Internal/Utils/PredicateTypesKey.cs @@ -1,24 +1,30 @@ using System; -using UnityEngine; namespace DCFApixels.DragonECS.Unity.Internal { internal readonly struct PredicateTypesKey : IEquatable { - public readonly Type[] Types; + public readonly Type TargetType; + public readonly Type[] AllowTypes; public readonly Type[] WithoutTypes; - public PredicateTypesKey(Type[] types) : this(types, Type.EmptyTypes) { } - public PredicateTypesKey(Type[] types, Type[] withoutTypes) + public PredicateTypesKey(Type signleType) : this(signleType, new Type[] { signleType } , Type.EmptyTypes) { } + public PredicateTypesKey(Type targetType, Type[] types) : this(targetType, types, Type.EmptyTypes) { } + public PredicateTypesKey(Type targetType, Type[] types, Type[] withoutTypes) { - Types = types; + if(targetType == null) + { + Throw.ArgumentNullException(); + } + TargetType = targetType; + AllowTypes = types; WithoutTypes = withoutTypes; } public bool Check(Type type) { - bool isAssignable = false; - foreach (Type predicateTypes in Types) + bool isAssignable = AllowTypes.Length == 0; + foreach (Type allowType in AllowTypes) { - if (predicateTypes.IsAssignableFrom(type)) + if (allowType.IsAssignableFrom(type)) { isAssignable = true; break; @@ -37,15 +43,20 @@ namespace DCFApixels.DragonECS.Unity.Internal } } - return isAssignable; + return isAssignable && TargetType.IsAssignableFrom(type); } public bool Equals(PredicateTypesKey other) { - if (Types.Length != other.Types.Length) { return false; } + if (AllowTypes.Length != other.AllowTypes.Length) { return false; } if (WithoutTypes.Length != other.WithoutTypes.Length) { return false; } - for (int i = 0; i < Types.Length; i++) + + if (TargetType != other.TargetType) { - if (Types[i] != other.Types[i]) + return false; + } + for (int i = 0; i < AllowTypes.Length; i++) + { + if (AllowTypes[i] != other.AllowTypes[i]) { return false; } @@ -65,8 +76,7 @@ namespace DCFApixels.DragonECS.Unity.Internal } public override int GetHashCode() { - return HashCode.Combine(Types, WithoutTypes); + return HashCode.Combine(TargetType, AllowTypes, 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/Throw.cs b/src/Internal/Utils/Throw.cs index 9fe02ff..f43649d 100644 --- a/src/Internal/Utils/Throw.cs +++ b/src/Internal/Utils/Throw.cs @@ -8,6 +8,10 @@ namespace DCFApixels.DragonECS.Unity.Internal { throw new ArgumentOutOfRangeException(); } + internal static void ArgumentNullException() + { + throw new ArgumentNullException(); + } internal static void Argument(string message) { throw new ArgumentException(message); diff --git a/src/Templates/EntityTemplate/ComponentTemplateProperty.cs b/src/Templates/EntityTemplate/ComponentTemplateProperty.cs index b881029..68f83ee 100644 --- a/src/Templates/EntityTemplate/ComponentTemplateProperty.cs +++ b/src/Templates/EntityTemplate/ComponentTemplateProperty.cs @@ -12,7 +12,10 @@ namespace DCFApixels.DragonECS public struct ComponentTemplateProperty : IEquatable { [SerializeReference] + [ReferenceDropDown] + [TypeMetaBlock] private ITemplateNode _template; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ComponentTemplateProperty(ITemplateNode template) { @@ -28,7 +31,7 @@ namespace DCFApixels.DragonECS public Type Type { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _template is IComponentTemplate tml ? tml.Type : _template.GetType(); } + get { return _template is IComponentTemplate tml ? tml.ComponentType : _template.GetType(); } } public bool IsNull { @@ -83,12 +86,19 @@ namespace DCFApixels.DragonECS public readonly struct Null { } } - public sealed class ComponentTemplateFieldAttribute : PropertyAttribute, IReferenceButtonAttribute + public sealed class ComponentTemplateFieldAttribute : PropertyAttribute, IReferenceDropDownAttribute { public Type[] PredicateTypes; - Type[] IReferenceButtonAttribute.PredicateTypes { get { return PredicateTypes; } } - bool IReferenceButtonAttribute.IsHideButtonIfNotNull { get { return true; } } - public ComponentTemplateFieldAttribute() { } + public readonly bool IsHideButtonIfNotNull = true; + Type[] IReferenceDropDownAttribute.PredicateTypes { get { return PredicateTypes; } } + bool IReferenceDropDownAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } } + public ComponentTemplateFieldAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty()) { } + public ComponentTemplateFieldAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { } + public ComponentTemplateFieldAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes) + { + IsHideButtonIfNotNull = isHideButtonIfNotNull; + PredicateTypes = predicateTypes; + Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); + } } - 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 0b3706a..088bd0c 100644 --- a/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs +++ b/src/Templates/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs @@ -9,200 +9,222 @@ namespace DCFApixels.DragonECS.Unity.Editors [CustomPropertyDrawer(typeof(ComponentTemplateProperty), true)] internal class ComponentTemplatePropertyDrawer : ExtendedPropertyDrawer { - private ComponentTemplateReferenceDrawer _drawer = new ComponentTemplateReferenceDrawer(new PredicateTypesKey(new Type[] { typeof(ITemplateNode) })); - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + //private EcsDragonFieldDrawer _drawer = new EcsDragonFieldDrawer(new PredicateTypesKey(typeof(ITemplateNode))); + //protected override float GetCustomHeight(SerializedProperty property, GUIContent label) + //{ + // property.Next(true); + // _drawer.StaticInit(); + // _drawer.Init(property); + // return _drawer.GetPropertyHeight(property, label); + //} + //protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) + //{ + // var root = property.Copy(); + // property.Next(true); + // _drawer.StaticInit(); + // _drawer.Init(property); + // _drawer.Draw(position, root, property, label); + //} + + protected override float GetCustomHeight(SerializedProperty property, GUIContent label) { property.Next(true); - _drawer.StaticInit(); - _drawer.Init(); - return _drawer.GetPropertyHeight(property, label); + return EditorGUI.GetPropertyHeight(property, label); } protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) { var root = property.Copy(); property.Next(true); - _drawer.StaticInit(); - _drawer.Init(); - _drawer.Draw(position, root, property, label); - } - } - [CustomPropertyDrawer(typeof(ComponentTemplateFieldAttribute), true)] - internal class ComponentTemplateReferenceDrawer : ExtendedPropertyDrawer - { - private const float DamagedComponentHeight = 18f * 2f; - private ComponentTemplatesDropDown _componentDropDown; - private PredicateTypesKey? _predicateOverride; - - - #region Properties - private float Padding => Spacing; - protected override bool IsInit => _componentDropDown != null; - #endregion - - public ComponentTemplateReferenceDrawer() { } - public ComponentTemplateReferenceDrawer(PredicateTypesKey key) - { - _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; - } - - [ThreadStatic] - private static SerializedProperty currentProperty; - private static void SelectComponent(ComponentTemplatesDropDown.Item item) - { - //EcsGUI.Changed = true; - object inst = item.Obj.CreateInstance(); - currentProperty.managedReferenceValue = inst; - currentProperty.isExpanded = false; - currentProperty.serializedObject.ApplyModifiedProperties(); - } - #endregion - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - bool isSerializeReference = property.propertyType == SerializedPropertyType.ManagedReference; - //#region No SerializeReference - //if (property.propertyType != SerializedPropertyType.ManagedReference) - //{ - // return EditorGUI.GetPropertyHeight(property, label); - //} - //#endregion - - if (isSerializeReference) - { - var instance = property.managedReferenceValue; - IComponentTemplate template = instance as IComponentTemplate; - if (instance == null) - { - return EditorGUIUtility.singleLineHeight + Padding * 2f; - } - - try - { - if (instance is ComponentTemplateBase customTemplate) - { - property = property.FindPropertyRelative("component"); - } - } - catch - { - property = null; - } - if (property == null) - { - return DamagedComponentHeight; - } - } - - int propCount = EcsGUI.GetChildPropertiesCount(property); - - return (propCount <= 0 ? EditorGUIUtility.singleLineHeight : EditorGUI.GetPropertyHeight(property, label)) + Padding * 4f; - } - - protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) - { - Draw(position, property, property, label); - } - public void Draw(Rect rect, SerializedProperty rootProperty, SerializedProperty property, GUIContent label) - { - bool isSerializeReference = property.propertyType == SerializedPropertyType.ManagedReference; - //#region No SerializeReference - //if (isSerializeReference == false) - //{ - // EditorGUI.PropertyField(position, property, label, true); - // return; - //} - //#endregion - - ITypeMeta meta = null; - SerializedProperty componentProp = property; - if (isSerializeReference) - { - var instance = property.managedReferenceValue; - if (instance == null) - { - DrawSelectionPopup(rect, property, label); - return; - } - - IComponentTemplate template = instance as IComponentTemplate; - if (componentProp.managedReferenceValue is ComponentTemplateBase customTemplate) - { - componentProp = property.FindPropertyRelative("component"); - } - if (componentProp == null) - { - DrawDamagedComponent(rect, "Damaged component template."); - return; - } - - meta = template is ITypeMeta metaOverride ? metaOverride : _predicateOverride.Value.Types[0].GetMeta(); - } - else - { - meta = fieldInfo.FieldType.GetMeta(); - } - - - if (EcsGUI.DrawTypeMetaBlock(ref rect, rootProperty, meta)) - { - return; - } - - label.text = meta.Name; - if (componentProp.propertyType == SerializedPropertyType.Generic) - { - EditorGUI.PropertyField(rect, componentProp, label, true); - } - else - { - EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true); - } - } - - private void DrawSelectionPopup(Rect position, SerializedProperty property, GUIContent label) - { - EditorGUI.LabelField(position, label); - Rect buttonRect = RectUtility.AddPadding(position, EditorGUIUtility.labelWidth, 0f, 0f, 0f); - if (GUI.Button(buttonRect, "Select")) - { - currentProperty = property; - _componentDropDown.Show(buttonRect); - } - } - private void DrawDamagedComponent(Rect position, string message) - { - EditorGUI.HelpBox(position, message, MessageType.Warning); + EditorGUI.PropertyField(position, property, label); } } + //[CustomPropertyDrawer(typeof(ComponentTemplateFieldAttribute), true)] + //internal class ComponentTemplateFieldDrawer : ExtendedPropertyDrawer + //{ + // private const float DamagedComponentHeight = 18f * 2f; + // private ComponentTemplatesDropDown _componentDropDown; + // private PredicateTypesKey? _predicateOverride; + // + // #region Properties + // private float Padding => Spacing; + // protected override bool IsInit => _componentDropDown != null; + // #endregion + // + // public ComponentTemplateFieldDrawer() { } + // public ComponentTemplateFieldDrawer(PredicateTypesKey key) + // { + // _predicateOverride = key; + // } + // + // #region Init + // protected override void OnInit(SerializedProperty property) + // { + // 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(typeof(ITemplateNode), types, withOutTypes); + // } + // else + // { + // key = new PredicateTypesKey(typeof(object), withOutTypes); + // } + // _predicateOverride = key; + // } + // _componentDropDown = ComponentTemplatesDropDown.Get(_predicateOverride.Value); + // _componentDropDown.OnSelected += SelectComponent; + // } + // + // [ThreadStatic] + // private static SerializedProperty currentProperty; + // private static void SelectComponent(ComponentTemplatesDropDown.Item item) + // { + // //EcsGUI.Changed = true; + // object inst = item.Obj.CreateInstance(); + // currentProperty.managedReferenceValue = inst; + // currentProperty.isExpanded = false; + // currentProperty.serializedObject.ApplyModifiedProperties(); + // } + // #endregion + // + // public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + // { + // bool isSerializeReference = property.propertyType == SerializedPropertyType.ManagedReference; + // //#region No SerializeReference + // //if (property.propertyType != SerializedPropertyType.ManagedReference) + // //{ + // // return EditorGUI.GetPropertyHeight(property, label); + // //} + // //#endregion + // + // if (isSerializeReference) + // { + // var instance = property.managedReferenceValue; + // IComponentTemplate template = instance as IComponentTemplate; + // if (instance == null) + // { + // return EditorGUIUtility.singleLineHeight + Padding * 2f; + // } + // + // try + // { + // if (instance is ComponentTemplateBase customTemplate) + // { + // property = property.FindPropertyRelative("component"); + // } + // } + // catch + // { + // property = null; + // } + // if (property == null) + // { + // return DamagedComponentHeight; + // } + // } + // + // int propCount = EcsGUI.GetChildPropertiesCount(property); + // + // return (propCount <= 0 ? EditorGUIUtility.singleLineHeight : EditorGUI.GetPropertyHeight(property, label)) + Padding * 4f; + // } + // + // protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) + // { + // Draw(position, property, property, label); + // } + // public void Draw(Rect rect, SerializedProperty rootProperty, SerializedProperty property, GUIContent label) + // { + // bool isSerializeReference = property.propertyType == SerializedPropertyType.ManagedReference; + // //#region No SerializeReference + // //if (isSerializeReference == false) + // //{ + // // EditorGUI.PropertyField(position, property, label, true); + // // return; + // //} + // //#endregion + // + // ITypeMeta meta = null; + // SerializedProperty componentProp = property; + // if (isSerializeReference) + // { + // var template = property.managedReferenceValue; + // if (template == null) + // { + // DrawSelectionPopup(rect, property, label); + // return; + // } + // + // IComponentTemplate componentTemplate = template as IComponentTemplate; + // if (componentProp.managedReferenceValue is ComponentTemplateBase customTemplate) + // { + // componentProp = property.FindPropertyRelative("component"); + // } + // if (componentProp == null) + // { + // DrawDamagedComponent(rect, "Damaged component template."); + // return; + // } + // + // meta = template as ITypeMeta; + // if (meta == null) + // { + // if (componentTemplate != null) + // { + // meta = componentTemplate.ComponentType.GetMeta(); + // } + // else + // { + // meta = template.GetMeta(); + // } + // } + // } + // else + // { + // meta = fieldInfo.FieldType.GetMeta(); + // } + // + // + // if (EcsGUI.DrawTypeMetaBlock(ref rect, rootProperty, meta).skip) + // { + // return; + // } + // + // label.text = meta.Name; + // if (componentProp.propertyType == SerializedPropertyType.Generic) + // { + // EditorGUI.PropertyField(rect, componentProp, label, true); + // } + // else + // { + // EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true); + // } + // } + // + // private void DrawSelectionPopup(Rect position, SerializedProperty property, GUIContent label) + // { + // EditorGUI.LabelField(position, label); + // Rect buttonRect = RectUtility.AddPadding(position, EditorGUIUtility.labelWidth, 0f, 0f, 0f); + // if (GUI.Button(buttonRect, "Select")) + // { + // currentProperty = property; + // _componentDropDown.Show(buttonRect); + // } + // } + // private void DrawDamagedComponent(Rect position, string message) + // { + // EditorGUI.HelpBox(position, message, MessageType.Warning); + // } + //} } #endif \ No newline at end of file diff --git a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs index 5c260db..725b784 100644 --- a/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs +++ b/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -10,13 +10,14 @@ namespace DCFApixels.DragonECS.Unity.Editors { internal abstract class EntityTemplateEditorBase : ExtendedEditor { - private ComponentTemplatesDropDown _componentDropDown; + private DragonFieldDropDown _componentDropDown; - private SerializedProperty _componentsProp; + private SerializedProperty _componentTemplatesProp; + private SerializedProperty _templatesProp; private ReorderableList _reorderableComponentsList; private int _reorderableComponentsListLastCount; - private static readonly Type[] _predicateTypes = new Type[] { typeof(ITemplateNode) }; + private static readonly Type[] _predicateTypes = new Type[] { typeof(IComponentTemplate), typeof(IEcsComponentMember) }; protected abstract bool IsSO { get; } @@ -24,11 +25,12 @@ namespace DCFApixels.DragonECS.Unity.Editors protected override bool IsInit { get { return _componentDropDown != null; } } protected override void OnInit() { - _componentDropDown = ComponentTemplatesDropDown.Get(new PredicateTypesKey(_predicateTypes, Type.EmptyTypes)); + _componentDropDown = DragonFieldDropDown.Get(new PredicateTypesKey(typeof(ITemplateNode), _predicateTypes, Type.EmptyTypes)); - _componentsProp = serializedObject.FindProperty("_componentTemplates"); + _componentTemplatesProp = serializedObject.FindProperty("_componentTemplates"); + _templatesProp = serializedObject.FindProperty("_templates"); - _reorderableComponentsList = new ReorderableList(serializedObject, _componentsProp, true, false, false, false); + _reorderableComponentsList = new ReorderableList(serializedObject, _componentTemplatesProp, true, false, false, false); _reorderableComponentsList.onAddCallback += OnReorderableComponentsListAdd; _reorderableComponentsList.onRemoveCallback += OnReorderableListRemove; _reorderableComponentsList.drawElementCallback += OnReorderableListDrawEmptyElement; @@ -73,48 +75,67 @@ namespace DCFApixels.DragonECS.Unity.Editors private float OnReorderableComponentsListElementHeight(int index) { - var componentProperty = GetTargetProperty(_componentsProp.GetArrayElementAtIndex(index)); - float result = EditorGUI.GetPropertyHeight(componentProperty); - return EcsGUI.GetTypeMetaBlockHeight(result) + Spacing * 2f; + SerializedProperty prop = _componentTemplatesProp.GetArrayElementAtIndex(index); + GUIContent label = UnityEditorUtility.GetLabelTemp(); + return EditorGUI.GetPropertyHeight(prop, label) + Spacing * 2f; + //var componentProperty = GetTargetProperty(_componentTemplatesProp.GetArrayElementAtIndex(index)); + //float result = EditorGUI.GetPropertyHeight(componentProperty); + //return EcsGUI.GetTypeMetaBlockHeight(result) + Spacing * 2f; } private void OnReorderableComponentsListDrawElement(Rect rect, int index, bool isActive, bool isFocused) { - if (index < 0 || Event.current.type == EventType.Used) { return; } + SerializedProperty prop = _componentTemplatesProp.GetArrayElementAtIndex(index); + GUIContent label = UnityEditorUtility.GetLabelTemp(); rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing); - using (EcsGUI.CheckChanged()) - { - SerializedProperty prop = _componentsProp.GetArrayElementAtIndex(index); - IComponentTemplate template = prop.managedReferenceValue as IComponentTemplate; - if (template == null || prop.managedReferenceValue == null) - { - //DrawDamagedComponent_Replaced(prop, index); - EditorGUI.PropertyField(rect, prop, UnityEditorUtility.GetLabel(prop.displayName), true); - return; - } - - var componentProp = GetTargetProperty(prop); - - - ITypeMeta meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.GetMeta(); - - if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _componentsProp, index, componentProp, meta)) - { - return; - } - - - GUIContent label = UnityEditorUtility.GetLabel(meta.Name); - if (componentProp.propertyType == SerializedPropertyType.Generic) - { - EditorGUI.PropertyField(rect, componentProp, label, true); - } - else - { - EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true); - } - - } + EditorGUI.PropertyField(rect, prop, label); + return; + //if (index < 0 || Event.current.type == EventType.Used) { return; } + //rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing); + //using (EcsGUI.CheckChanged()) + //{ + // SerializedProperty prop = _componentTemplatesProp.GetArrayElementAtIndex(index); + // + // var template = prop.managedReferenceValue; + // if (template == null) + // { + // //DrawDamagedComponent_Replaced(prop, index); + // EditorGUI.PropertyField(rect, prop, UnityEditorUtility.GetLabel(prop.displayName), true); + // return; + // } + // IComponentTemplate componentTemplate = template as IComponentTemplate; + // var componentProp = GetTargetProperty(prop); + // + // ITypeMeta meta = template as ITypeMeta; + // if(meta == null) + // { + // if (componentTemplate != null) + // { + // meta = componentTemplate.ComponentType.GetMeta(); + // } + // else + // { + // meta = template.GetMeta(); + // } + // } + // + // if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _componentTemplatesProp, index, componentProp, meta).skip) + // { + // return; + // } + // + // + // GUIContent label = UnityEditorUtility.GetLabel(meta.Name); + // if (componentProp.propertyType == SerializedPropertyType.Generic) + // { + // EditorGUI.PropertyField(rect, componentProp, label, true); + // } + // else + // { + // EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true); + // } + // + //} } private void OnReorderableComponentsListAdd(ReorderableList list) @@ -147,6 +168,8 @@ namespace DCFApixels.DragonECS.Unity.Editors { Init(); + + if (IsSO) { EcsGUI.Layout.ManuallySerializeButton(targets); @@ -186,21 +209,32 @@ namespace DCFApixels.DragonECS.Unity.Editors SerializedProperty iterator = serializedObject.GetIterator(); iterator.NextVisible(true); + using (EcsGUI.Disable) + { + EditorGUILayout.PropertyField(iterator, true); + } while (iterator.NextVisible(false)) { - if (_componentsProp != null && iterator.name == _componentsProp.name) + if ((_componentTemplatesProp != null && iterator.name == _componentTemplatesProp.name) || + (_templatesProp != null && iterator.name == _templatesProp.name)) { - using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) - { - DrawTop(_componentsProp); - _reorderableComponentsList.DoLayoutList(); - } + } else { EditorGUILayout.PropertyField(iterator, true); } } + + if (_templatesProp != null) + { + EditorGUILayout.PropertyField(_templatesProp, true); + } + using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) + { + DrawTop(_componentTemplatesProp); + _reorderableComponentsList.DoLayoutList(); + } } private void DrawTop(SerializedProperty componentsProp) { diff --git a/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs b/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs index 5f31235..70c0e81 100644 --- a/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs +++ b/src/Templates/EntityTemplate/Templates/ComponentTemplateBase.cs @@ -4,6 +4,7 @@ using DCFApixels.DragonECS.Unity.Internal; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using UnityEngine; @@ -14,7 +15,7 @@ namespace DCFApixels.DragonECS public interface IComponentTemplate : ITemplateNode { #region Properties - Type Type { get; } + Type ComponentType { get; } bool IsUnique { get; } #endregion @@ -33,16 +34,11 @@ namespace DCFApixels.DragonECS } [Serializable] - public abstract class ComponentTemplateBase : IComponentTemplate, ITypeMeta + [MetaProxy(typeof(ComponentTemplateMetaProxy))] + public abstract class ComponentTemplateBase : IComponentTemplate { #region Properties - public abstract Type Type { get; } - public virtual ITypeMeta BaseMeta { get { return null; } } - public virtual string Name { get { return string.Empty; } } - public virtual MetaColor Color { get { return new MetaColor(MetaColor.Black); } } - public virtual MetaGroup Group { get { return MetaGroup.Empty; } } - public virtual MetaDescription Description { get { return MetaDescription.Empty; } } - public virtual IReadOnlyList Tags { get { return Array.Empty(); } } + public abstract Type ComponentType { get; } public virtual bool IsUnique { get { return true; } } #endregion @@ -54,67 +50,136 @@ namespace DCFApixels.DragonECS public abstract void Apply(short worldID, int entityID); #endregion + + protected class ComponentTemplateMetaProxy : MetaProxy + { + protected static TypeMeta Meta; + public override string Name { get { return Meta?.Name; } } + public override MetaColor? Color { get { return Meta?.Color; } } + public override MetaGroup Group { get { return Meta?.Group; } } + public override MetaDescription Description { get { return Meta?.Description; } } + public override IEnumerable Tags { get { return Meta?.Tags; } } + public ComponentTemplateMetaProxy(Type type) : base(type) + { + if (type.IsGenericType && type.ContainsGenericParameters == false) + { + var g = type.GetGenericArguments(); + if (g.Length == 1) + { + Meta = g[0].GetMeta(); + } + } + } + } } [Serializable] [StructLayout(LayoutKind.Sequential)] public abstract class ComponentTemplateBase : ComponentTemplateBase, ICloneable - where T : struct { protected static readonly TypeMeta Meta = EcsDebugUtility.GetTypeMeta(); - private static bool _defaultValueTypeInit = false; - private static T _defaultValueType; - protected static T DefaultValueType + private static bool _defaultValueInit = false; + private static bool _hasDefaultValue = false; + private static T _defaultValue; + private static ICloneable _defaultValueCloneable; + private static CloneMethod _defaultValueCloneMethod; + private enum CloneMethod + { + Set, + Clone_Reflection, + ICloneable, + } + protected static void InitStatic() + { + if (_defaultValueInit == false) + { + _hasDefaultValue = false; + Type type = typeof(T); + FieldInfo field; + field = type.GetField("Default", BindingFlags.Static | BindingFlags.Public); + if (field != null && field.FieldType == type) + { + _defaultValue = (T)field.GetValue(null); + _hasDefaultValue = true; + } + if(_hasDefaultValue == false) + { + field = type.GetField("Empty", BindingFlags.Static | BindingFlags.Public); + if (field != null && field.FieldType == type) + { + _defaultValue = (T)field.GetValue(null); + _hasDefaultValue = true; + } + } + if (_defaultValue == null) + { + _hasDefaultValue = false; + } + + if (_hasDefaultValue) + { + _defaultValueCloneable = _defaultValue as ICloneable; + _defaultValueCloneMethod = CloneMethod.Set; + + if (type.IsValueType == false) + { + _defaultValueCloneMethod = CloneMethod.Clone_Reflection; + } + if (_defaultValueCloneable != null) + { + _defaultValueCloneMethod = CloneMethod.ICloneable; + } + } + + _defaultValueInit = true; + } + } + protected virtual T DefaultComponent { get { - if (_defaultValueTypeInit == false) + if (_hasDefaultValue) { - Type type = typeof(T); - if (type.IsValueType) - { - FieldInfo field; - field = type.GetField("Default", BindingFlags.Static | BindingFlags.Public); - if (field != null && field.FieldType == type) - { - _defaultValueType = (T)field.GetValue(null); - } - field = type.GetField("Empty", BindingFlags.Static | BindingFlags.Public); - if (field != null && field.FieldType == type) - { - _defaultValueType = (T)field.GetValue(null); - } - } - _defaultValueTypeInit = true; + return CloneComponent(_defaultValue); } - return _defaultValueType; + return default; } } [SerializeField] - protected T component = DefaultValueType; + protected T component; [SerializeField] [HideInInspector] private byte _offset; // Avoids the error "Cannot get managed reference index with out bounds offset" - #region Properties - public sealed override ITypeMeta BaseMeta { get { return Meta; } } - public sealed override Type Type { get { return typeof(T); } } - public override string Name { get { return Meta.Name; } } - public override MetaColor Color { get { return Meta.Color; } } - public override MetaGroup Group { get { return Meta.Group; } } - public override MetaDescription Description { get { return Meta.Description; } } - public override IReadOnlyList Tags { get { return Meta.Tags; } } - #endregion + public ComponentTemplateBase() + { + InitStatic(); + component = DefaultComponent; + } + + public sealed override Type ComponentType { get { return typeof(T); } } #region Methods public sealed override object GetRaw() { return component; } public sealed override void SetRaw(object raw) { component = (T)raw; } - protected virtual T CloneComponent() { return component; } + protected virtual T CloneComponent(T component) + { + switch (_defaultValueCloneMethod) + { + case CloneMethod.Set: + return component; + case CloneMethod.Clone_Reflection: + return (T)component.Clone_Reflection(); + case CloneMethod.ICloneable: + return (T)_defaultValueCloneable.Clone(); + } + return default; + } object ICloneable.Clone() { ComponentTemplateBase templateClone = (ComponentTemplateBase)MemberwiseClone(); - templateClone.component = CloneComponent(); + templateClone.component = CloneComponent(component); return templateClone; } #endregion @@ -175,7 +240,9 @@ namespace DCFApixels.DragonECS.Unity.Editors { if (_meta == null) { - _meta = ComponentType.GetMeta(); + { + _meta = ComponentType.GetMeta(); + } } return _meta; } @@ -194,7 +261,7 @@ namespace DCFApixels.DragonECS.Unity.Editors field = Type.GetField("Default", BindingFlags.Static | BindingFlags.Public); if (field != null && field.FieldType == Type) { - _defaultValueDummy = field.GetValue(null); + _defaultValueDummy = field.GetValue(null).Clone_Reflection(); } if(_defaultValueDummy == null) @@ -202,7 +269,7 @@ namespace DCFApixels.DragonECS.Unity.Editors field = Type.GetField("Empty", BindingFlags.Static | BindingFlags.Public); if (field != null && field.FieldType == Type) { - _defaultValueDummy = field.GetValue(null); + _defaultValueDummy = field.GetValue(null).Clone_Reflection(); } } } @@ -216,15 +283,17 @@ namespace DCFApixels.DragonECS.Unity.Editors Type = type; IsUnique = false; - if (typeof(IComponentTemplate).IsAssignableFrom(type)) + if (type.GetInterfaces().Contains(typeof(ITypeMeta))) + { + var metaOverride = (ITypeMeta)Activator.CreateInstance(type); + _meta = metaOverride; + } + + if (type.GetInterfaces().Contains(typeof(IComponentTemplate))) { var ct = (IComponentTemplate)Activator.CreateInstance(type); IsUnique = ct.IsUnique; - ComponentType = ct.Type; - if (ct is ITypeMeta metaOverride) - { - _meta = metaOverride; - } + ComponentType = ct.ComponentType; } else { diff --git a/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs b/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs index 63a9fa2..0ffeb80 100644 --- a/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs +++ b/src/Templates/EntityTemplate/Templates/MonoEntityTemplate.cs @@ -2,6 +2,7 @@ #undef DEBUG #endif using DCFApixels.DragonECS.Unity; +using DCFApixels.DragonECS.Unity.Internal; using System; using System.Collections.Generic; using System.Linq; @@ -24,8 +25,10 @@ namespace DCFApixels.DragonECS public class MonoEntityTemplate : MonoEntityTemplateBase, ITemplateNode { [SerializeReference] - [ReferenceButton(true, typeof(ITemplateNode))] + [ReferenceDropDown(true)] + [TypeMetaBlock] [FormerlySerializedAs("_components")] + [ArrayElement] private ITemplateNode[] _componentTemplates; #region Methods diff --git a/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs b/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs index c4a0ed6..e4a7d84 100644 --- a/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs +++ b/src/Templates/EntityTemplate/Templates/ScriptableEntityTemplate.cs @@ -25,7 +25,7 @@ namespace DCFApixels.DragonECS [SerializeField] private ScriptableEntityTemplateBase[] _templates; [SerializeReference] - [ReferenceButton(true, typeof(ITemplateNode))] + [ReferenceDropDown(true)] [FormerlySerializedAs("_components")] private ITemplateNode[] _componentTemplates; diff --git a/src/Templates/PipelineTemplate/Editor/PipelineTemplateEditor.cs b/src/Templates/PipelineTemplate/Editor/PipelineTemplateEditor.cs index b1d120b..cf9f890 100644 --- a/src/Templates/PipelineTemplate/Editor/PipelineTemplateEditor.cs +++ b/src/Templates/PipelineTemplate/Editor/PipelineTemplateEditor.cs @@ -119,7 +119,7 @@ namespace DCFApixels.DragonECS.Unity.Editors bool isNull = targetProp.managedReferenceValue == null; ITypeMeta meta = isNull ? null : targetProp.managedReferenceValue.GetMeta(); - if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _recordsProp, index, prop, meta)) + if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _recordsProp, index, prop, meta).skip) { return; } diff --git a/src/Templates/PipelineTemplate/Editor/PipelineTemplateUtilityRecordDrawer.cs b/src/Templates/PipelineTemplate/Editor/PipelineTemplateUtilityRecordDrawer.cs index aea8d46..38a5a0e 100644 --- a/src/Templates/PipelineTemplate/Editor/PipelineTemplateUtilityRecordDrawer.cs +++ b/src/Templates/PipelineTemplate/Editor/PipelineTemplateUtilityRecordDrawer.cs @@ -41,7 +41,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } } - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + protected override float GetCustomHeight(SerializedProperty property, GUIContent label) { float result = 0f; if (IsArrayElement == false) diff --git a/src/Templates/PipelineTemplate/PipelineTemplateUtility.cs b/src/Templates/PipelineTemplate/PipelineTemplateUtility.cs index 363f17c..7a3200c 100644 --- a/src/Templates/PipelineTemplate/PipelineTemplateUtility.cs +++ b/src/Templates/PipelineTemplate/PipelineTemplateUtility.cs @@ -103,8 +103,8 @@ namespace DCFApixels.DragonECS.Unity public struct Record { [SerializeReference] - [ReferenceButton(true, typeof(IEcsModule), typeof(IEcsProcess))] - [ReferenceButtonWithOut(typeof(IEcsRunner))] + [ReferenceDropDown(true, typeof(IEcsModule), typeof(IEcsProcess))] + [ReferenceDropDownWithout(typeof(IEcsRunner))] [ArrayElement] public object target;// нельзя менять поярдок полей, иначе это поломает отрисовку в инспекторе изза применения property.Next(bool); public AddParams parameters; diff --git a/src/Utils/ReferenceButtonAttribute.cs b/src/Utils/ReferenceButtonAttribute.cs index de76d54..5a67249 100644 --- a/src/Utils/ReferenceButtonAttribute.cs +++ b/src/Utils/ReferenceButtonAttribute.cs @@ -2,35 +2,637 @@ #undef DEBUG #endif using DCFApixels.DragonECS.Unity.Editors; +using DCFApixels.DragonECS.Unity.Internal; using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; using UnityEngine; namespace DCFApixels.DragonECS { - public sealed class ReferenceButtonAttribute : PropertyAttribute, IReferenceButtonAttribute + internal interface IReferenceDropDownAttribute { - public readonly Type[] PredicateTypes; + Type[] PredicateTypes { get; } + bool IsHideButtonIfNotNull { get; } + } + //public sealed class ReferenceButtonAttribute : PropertyAttribute, IReferenceDropDownAttribute + //{ + // public readonly Type[] PredicateTypes; + // public readonly bool IsHideButtonIfNotNull; + // Type[] IReferenceDropDownAttribute.PredicateTypes { get { return PredicateTypes; } } + // bool IReferenceDropDownAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } } + // public ReferenceButtonAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty()) { } + // public ReferenceButtonAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { } + // public ReferenceButtonAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes) + // { + // IsHideButtonIfNotNull = isHideButtonIfNotNull; + // PredicateTypes = predicateTypes; + // Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); + // } + //} + //public sealed class ReferenceButtonWithOutAttribute : Attribute + //{ + // public readonly Type[] PredicateTypes; + // [Obsolete("With empty parameters, this attribute makes no sense.", true)] + // public ReferenceButtonWithOutAttribute() : this(Array.Empty()) { } + // public ReferenceButtonWithOutAttribute(params Type[] predicateTypes) + // { + // PredicateTypes = predicateTypes; + // Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); + // } + //} + + public sealed class ReferenceDropDownAttribute : PropertyAttribute, IReferenceDropDownAttribute + { + public readonly Type[] AllowTypes; public readonly bool IsHideButtonIfNotNull; - Type[] IReferenceButtonAttribute.PredicateTypes { get { return PredicateTypes; } } - bool IReferenceButtonAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } } - public ReferenceButtonAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty()) { } - public ReferenceButtonAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { } - public ReferenceButtonAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes) + Type[] IReferenceDropDownAttribute.PredicateTypes { get { return AllowTypes; } } + bool IReferenceDropDownAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } } + public ReferenceDropDownAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty()) { } + public ReferenceDropDownAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { } + public ReferenceDropDownAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes) { IsHideButtonIfNotNull = isHideButtonIfNotNull; - PredicateTypes = predicateTypes; + AllowTypes = predicateTypes; Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); } } - public sealed class ReferenceButtonWithOutAttribute : Attribute + public sealed class ReferenceDropDownWithoutAttribute : Attribute { public readonly Type[] PredicateTypes; [Obsolete("With empty parameters, this attribute makes no sense.", true)] - public ReferenceButtonWithOutAttribute() : this(Array.Empty()) { } - public ReferenceButtonWithOutAttribute(params Type[] predicateTypes) + public ReferenceDropDownWithoutAttribute() : this(Array.Empty()) { } + public ReferenceDropDownWithoutAttribute(params Type[] predicateTypes) { PredicateTypes = predicateTypes; Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); } } -} \ No newline at end of file + public sealed class TypeMetaBlockAttribute : PropertyAttribute { } +} + + + + + + + + +#if UNITY_EDITOR +namespace DCFApixels.DragonECS.Unity.Editors +{ + [CustomPropertyDrawer(typeof(ReferenceDropDownAttribute), true)] + [CustomPropertyDrawer(typeof(TypeMetaBlockAttribute), true)] + internal class EcsDragonFieldDrawer : ExtendedPropertyDrawer + { + private const float DamagedComponentHeight = 18f * 2f; + private DragonFieldDropDown _dropDown; + private PredicateTypesKey? _predicateOverride; + + private ReferenceDropDownAttribute ReferenceDropDownAttribute; + private ReferenceDropDownWithoutAttribute ReferenceDropDownWithoutAttribute; + private TypeMetaBlockAttribute TypeMetaBlockAttribute; + + private bool _isInit = false; + private bool _hasSerializableData; + + [ThreadStatic] + private static int _skips = 0; + private bool CheckSkip() + { + if (_skips > 0) + { + _skips--; + return true; + } + int count = 0; + if (ReferenceDropDownAttribute != null) { count++; } + if (TypeMetaBlockAttribute != null) { count++; } + + _skips = count - 1; + return false; + } + + #region Properties + private float Padding => Spacing; + protected override bool IsInit => _isInit; + private bool IsDrawDropDown => ReferenceDropDownAttribute != null; + private bool IsDrawMetaBlock => TypeMetaBlockAttribute != null; + #endregion + + public EcsDragonFieldDrawer() { } + public EcsDragonFieldDrawer(PredicateTypesKey key) + { + _predicateOverride = key; + } + + #region Init + protected override void OnInit(SerializedProperty property) + { + PredicateTypesKey key; + _hasSerializableData = true; + + if (fieldInfo != null) + { + if (property.propertyType == SerializedPropertyType.ManagedReference) + { + _hasSerializableData = property.HasSerializableData(); + } + foreach (var atrRaw in Attributes) + { + switch (atrRaw) + { + case ReferenceDropDownAttribute atr: ReferenceDropDownAttribute = atr; break; + case ReferenceDropDownWithoutAttribute atr: ReferenceDropDownWithoutAttribute = atr; break; + case TypeMetaBlockAttribute atr: TypeMetaBlockAttribute = atr; break; + } + } + } + if (_predicateOverride == null && fieldInfo != null) + { + + var targetType = fieldInfo.FieldType; + if (ReferenceDropDownAttribute != null) + { + Type[] withOutTypes = ReferenceDropDownWithoutAttribute != null ? ReferenceDropDownWithoutAttribute.PredicateTypes : Type.EmptyTypes; + + bool allAssignableTypes = targetType != typeof(ITemplateNode); + + var types = ReferenceDropDownAttribute.AllowTypes; + if (types == null || types.Length == 0) + { + if (allAssignableTypes) + { + types = new Type[] { targetType }; + } + else + { + types = new Type[] { typeof(IComponentTemplate), typeof(IEcsComponentMember) }; + } + } + key = new PredicateTypesKey(targetType, types, withOutTypes); + } + else + { + key = new PredicateTypesKey(targetType, new Type[] { targetType }); + } + _predicateOverride = key; + } + + if (IsDrawDropDown) + { + _dropDown = DragonFieldDropDown.Get(_predicateOverride.Value); + _dropDown.OnSelected += SelectComponent; + } + + _isInit = true; + } + + [ThreadStatic] + private static SerializedProperty currentProperty; + private static void SelectComponent(DragonFieldDropDown.Item item) + { + //EcsGUI.Changed = true; + if (item.Obj == null) + { + currentProperty.managedReferenceValue = null; + } + else + { + currentProperty.managedReferenceValue = item.Obj.CreateInstance(); + currentProperty.isExpanded = false; + } + currentProperty.serializedObject.ApplyModifiedProperties(); + EcsGUI.DelayedChanged = true; + } + #endregion + + protected override float GetCustomHeight(SerializedProperty property, GUIContent label) + { + if (CheckSkip()) { return EditorGUI.GetPropertyHeight(property, label); } + bool isSerializeReference = property.propertyType == SerializedPropertyType.ManagedReference; + + SerializedProperty componentProp = property; + if (isSerializeReference) + { + var instance = property.managedReferenceValue; + if (instance == null) + { + float result = EditorGUIUtility.singleLineHeight; + if (IsDrawMetaBlock) + { + result += Padding * 2f; + } + return result; + } + + try + { + if (instance is ComponentTemplateBase customTemplate) + { + componentProp = property.FindPropertyRelative("component"); + } + } + catch + { + componentProp = property; + } + if (componentProp == null) + { + return DamagedComponentHeight; + } + } + + { + float result = EditorGUIUtility.singleLineHeight; + if (_hasSerializableData) + { + result = EditorGUI.GetPropertyHeight(componentProp, label); + } + if (IsDrawMetaBlock) + { + result += Padding * 4f; + } + return result; + } + } + + protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) + { + Draw(position, property, property, label); + } + public void Draw(Rect rect, SerializedProperty rootProperty, SerializedProperty property, GUIContent label) + { + if (CheckSkip()) { EditorGUI.PropertyField(rect, property, label, true); return; } + bool isSerializeReference = property.propertyType == SerializedPropertyType.ManagedReference; + var e = Event.current; + + ITypeMeta meta = null; + SerializedProperty componentProp = property; + bool isDrawProperty = true; + bool isDrawDropDown = IsDrawDropDown && isSerializeReference; + + if (isSerializeReference) + { + var template = property.managedReferenceValue; + + if (template is ComponentTemplateBase) + { + componentProp = property.FindPropertyRelative("component"); + } + if (componentProp == null) + { + DrawDamagedComponent(rect, "Damaged component template."); + return; + } + if (template == null) + { + isDrawProperty = false; + } + + //meta = template as ITypeMeta; + if (meta == null) + { + if (template is IComponentTemplate componentTemplate) + { + meta = componentTemplate.ComponentType.GetMeta(); + } + else + { + meta = template.GetMeta(); + } + } + + if (isDrawDropDown && template != null && ReferenceDropDownAttribute.IsHideButtonIfNotNull) + { + isDrawDropDown = false; + } + } + else + { + meta = fieldInfo.FieldType.GetMeta(); + } + + + + float selectionButtonRightOffset = 0f; + + if (isDrawProperty) + { + if (IsDrawMetaBlock) + { + ref var r = ref rect; + var (skip, optionsWidth) = EcsGUI.DrawTypeMetaBlock(ref r, rootProperty, meta); + selectionButtonRightOffset = optionsWidth; + if (skip) + { + return; + } + } + } + + + + + + if (isDrawProperty) + { + if (IsArrayElement) + { + label.text = meta.Name; + } + + var fieldRect = rect; + + if (property != componentProp && + componentProp.propertyType != SerializedPropertyType.Generic && + componentProp.propertyType != SerializedPropertyType.ManagedReference) + { + fieldRect.xMax -= selectionButtonRightOffset; + isDrawDropDown = false; + } + + var et = e.type; + + if (_hasSerializableData) + { + EditorGUI.PropertyField(fieldRect, componentProp, label, true); + } + else + { + EditorGUI.LabelField(rect, label); + } + + var labelRect = rect; + labelRect.width = EditorGUIUtility.labelWidth; + labelRect.xMin -= 20f; + if (e.type == EventType.Used && EcsGUI.HitTest(labelRect, e) == false) + { + e.type = et; + } + + } + else + { + EditorGUI.LabelField(rect, label); + } + + + + + if (isDrawDropDown) + { + rect.xMax -= selectionButtonRightOffset; + DrawSelectionDropDown(rect, property, label); + } + + } + + + + + + private void DrawSelectionDropDown(Rect rect, SerializedProperty property, GUIContent label) + { + if (rect.width < 0) { return; } + + var position = IsArrayElement ? rect : rect.AddPadding(EditorGUIUtility.labelWidth, 0f, 0f, 0f); + position.height = OneLineHeight; + + bool isHideButtonIfNotNull = ReferenceDropDownAttribute.IsHideButtonIfNotNull; + object obj = property.hasMultipleDifferentValues ? null : property.managedReferenceValue; + + string text = obj == null ? "Select..." : obj.GetMeta().Name; + if (!isHideButtonIfNotNull || obj == null) + { + if (GUI.Button(position, text, EditorStyles.layerMaskField)) + { + currentProperty = property; + _dropDown.OpenForField(position, property); + } + } + else + { + GUI.Label(position, text); + } + } + private void DrawDamagedComponent(Rect position, string message) + { + EditorGUI.HelpBox(position, message, MessageType.Warning); + } + } + + + + + + + + + + + internal class DragonFieldDropDown : MetaObjectsDropDown + { + private DragonFieldDropDown() { } + + private bool _isCheckUnique; + private SerializedProperty _arrayProperty; + private SerializedProperty _fieldProperty; + + public static Dictionary _dropDownsCache = new Dictionary(32); + public static DragonFieldDropDown Get(PredicateTypesKey key) + { + if (_dropDownsCache.TryGetValue(key, out var result) == false) + { + result = new DragonFieldDropDown(); + IEnumerable<(DragonFieldCahce template, ITypeMeta meta)> itemMetaPairs = DragonFieldCahce.All.ToArray() + .Where(o => + { + return key.Check(o.Type); + + }) + .Select(o => + { + return (o, (ITypeMeta)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; + _arrayProperty = arrayProperty; + _fieldProperty = null; + Show(position); + } + public void OpenForField(Rect position, SerializedProperty fieldProperty) + { + _isCheckUnique = false; + _arrayProperty = null; + _fieldProperty = fieldProperty; + Show(position); + } + + protected override void ItemSelected(Item item) + { + if (item.Obj == null) + { + _fieldProperty.managedReferenceValue = null; + _fieldProperty.serializedObject.ApplyModifiedProperties(); + return; + } + + Type componentType = item.Obj.GetType(); + var data = item.Obj; + + if (_arrayProperty != null && data != null) + { + int index = _arrayProperty.arraySize; + if (_isCheckUnique) + { + if (data.IsUnique) + { + for (int i = 0, iMax = _arrayProperty.arraySize; i < iMax; i++) + { + if (_arrayProperty.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType) + { + return; + } + } + } + } + _arrayProperty.arraySize += 1; + _fieldProperty = _arrayProperty.GetArrayElementAtIndex(index); + } + + if (_fieldProperty != null) + { + _fieldProperty.managedReferenceValue = data.CreateInstance(); + _fieldProperty.serializedObject.ApplyModifiedProperties(); + } + + //Event.current.Use(); + } + } + + + + + + + + + + + + + internal class DragonFieldCahce + { + private static DragonFieldCahce[] _all; + internal static IReadOnlyList All + { + get { return _all; } + } + static DragonFieldCahce() { StaticInit(); } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void StaticInit() + { + List list = new List(UnityEditorUtility._serializableTypes.Length); + foreach (var type in UnityEditorUtility._serializableTypes) + { + DragonFieldCahce element = new DragonFieldCahce(type); + list.Add(element); + } + _all = list.ToArray(); + } + + + public readonly Type Type; + public readonly Type ComponentType; + public readonly bool IsUnique; + private TypeMeta _meta; + public TypeMeta Meta + { + get + { + if (_meta == null) + { + { + _meta = Type.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).Clone_Reflection(); + } + + if (_defaultValueDummy == null) + { + field = Type.GetField("Empty", BindingFlags.Static | BindingFlags.Public); + if (field != null && field.FieldType == Type) + { + _defaultValueDummy = field.GetValue(null).Clone_Reflection(); + } + } + } + _defaultValueTypeInit = true; + } + return _defaultValueDummy; + } + } + public DragonFieldCahce(Type type) + { + Type = type; + IsUnique = false; + + if (type.GetInterfaces().Contains(typeof(IComponentTemplate))) + { + var ct = (IComponentTemplate)Activator.CreateInstance(type); + IsUnique = ct.IsUnique; + ComponentType = ct.ComponentType; + } + else + { + ComponentType = Type; + } + } + public object CreateInstance() + { + if (DefaultValue != null) + { + return DefaultValue.Clone_Reflection(); + } + return Activator.CreateInstance(Type); + } + + public override string ToString() + { + return Type.ToString(); + } + } +} +#endif \ No newline at end of file