rework components display

This commit is contained in:
Mikhail 2026-04-14 10:15:44 +08:00
parent a23fbb712e
commit 2c5461fca1
22 changed files with 1434 additions and 576 deletions

View File

@ -45,16 +45,9 @@ namespace DCFApixels.DragonECS
[MetaGroup(EcsUnityConsts.PACK_GROUP, OTHER_GROUP)] [MetaGroup(EcsUnityConsts.PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "Template for UnityComponent<T>")] [MetaDescription(AUTHOR, "Template for UnityComponent<T>")]
[MetaID("DragonECS_13DAACF9910155DD27F822442987E0AE")] [MetaID("DragonECS_13DAACF9910155DD27F822442987E0AE")]
[MetaProxy(typeof(UnityComponentTemplate<>.UnityComponentMetaProxy))]
public abstract class UnityComponentTemplate<T> : ComponentTemplateBase<UnityComponent<T>> where T : Component public abstract class UnityComponentTemplate<T> : ComponentTemplateBase<UnityComponent<T>> 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) public sealed override void Apply(short worldID, int entityID)
{ {
EcsWorld.GetPoolInstance<EcsPool<UnityComponent<T>>>(worldID).TryAddOrGet(entityID) = component; EcsWorld.GetPoolInstance<EcsPool<UnityComponent<T>>>(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) { }
}
} }
} }

View File

@ -186,7 +186,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
return false; return false;
} }
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) protected override float GetCustomHeight(SerializedProperty property, GUIContent label)
{ {
const float UNITY_HEIGHT_CONSTANT = 18f; const float UNITY_HEIGHT_CONSTANT = 18f;
if (property.hasMultipleDifferentValues) if (property.hasMultipleDifferentValues)

View File

@ -12,6 +12,74 @@ namespace DCFApixels.DragonECS.Unity.Editors
internal class WorldQueriesMonitorEditor : ExtendedEditor<WorldQueriesMonitor> internal class WorldQueriesMonitorEditor : ExtendedEditor<WorldQueriesMonitor>
{ {
private GUIStyle _headerStyle; 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<char> 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() private void CopyToClipboard()
{ {
@ -148,21 +216,42 @@ namespace DCFApixels.DragonECS.Unity.Editors
int i = 0; int i = 0;
foreach (var executor in executors) foreach (var executor in executors)
{ {
bool cheack(ReadOnlySpan<Type> types, string searchPattern) bool cheack(ReadOnlySpan<Type> types, ReadOnlySpan<char> searchPatternRaw)
{ {
foreach (var type in types) foreach (var type in types)
{ {
if(type.Name.Contains(searchPattern, StringComparison.OrdinalIgnoreCase)) if(type.Name.AsSpan().Contains(searchPatternRaw, StringComparison.OrdinalIgnoreCase))
{ {
return true; return true;
} }
} }
return false; return false;
} }
if (!HasSearchPattern ||
cheack(executor.Mask.GetIncTypes_Debug(), searchPattern) || bool isDraw = false;
cheack(executor.Mask.GetExcTypes_Debug(), searchPattern) || if (HasSearchPattern)
cheack(executor.Mask.GetAnyTypes_Debug(), searchPattern)) {
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++); DrawQueryInfo(executor, i++);
} }

View File

@ -29,8 +29,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
{ (byte)AddParamsFlags.NoImport | 7, "NoImport, Layer, Order, IsUnique" }, { (byte)AddParamsFlags.NoImport | 7, "NoImport, Layer, Order, IsUnique" },
{ byte.MaxValue, "NoImport, Layer, Order, IsUnique" }, { byte.MaxValue, "NoImport, Layer, Order, IsUnique" },
}; };
protected override float GetCustomHeight(SerializedProperty property, GUIContent label)
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{ {
//return !property.isExpanded ? //return !property.isExpanded ?
// EditorGUIUtility.singleLineHeight + Spacing : // EditorGUIUtility.singleLineHeight + Spacing :

View File

@ -18,6 +18,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
[CustomPropertyDrawer(typeof(CustomToggleAttribute))] [CustomPropertyDrawer(typeof(CustomToggleAttribute))]
internal class LeftToggleAttributeDrawer : ExtendedPropertyDrawer<CustomToggleAttribute> internal class LeftToggleAttributeDrawer : ExtendedPropertyDrawer<CustomToggleAttribute>
{ {
protected override float GetCustomHeight(SerializedProperty property, GUIContent label)
{
return OneLineHeight + Spacing;
}
protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label)
{ {
if (property.propertyType != SerializedPropertyType.Boolean) if (property.propertyType != SerializedPropertyType.Boolean)

View File

@ -426,8 +426,8 @@ namespace DCFApixels.DragonECS.Unity.Editors
using (SetAlpha(0)) using (SetAlpha(0))
{ {
bool result = GUI.Button(position, string.Empty, EditorStyles.miniButtonMid); bool result = GUI.Button(position, string.Empty, EditorStyles.miniButtonMid);
var current = Event.current; var currentEvent = Event.current;
return (GUI.enabled && HitTest(position, current), result); return (GUI.enabled && HitTest(position, currentEvent), result);
} }
} }
public static bool IconHoverScan(Rect position, Event current) public static bool IconHoverScan(Rect position, Event current)
@ -486,11 +486,13 @@ namespace DCFApixels.DragonECS.Unity.Editors
if (current.type == EventType.MouseUp) if (current.type == EventType.MouseUp)
{ {
EditorGUIUtility.PingObject(script); EditorGUIUtility.PingObject(script);
Event.current.Use();
} }
else if (current.type == EventType.MouseDown && current.clickCount >= 2) else if (current.type == EventType.MouseDown && current.clickCount >= 2)
{ {
//UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(); //TODO //UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(); //TODO
AssetDatabase.OpenAsset(script); AssetDatabase.OpenAsset(script);
Event.current.Use();
} }
} }
} }
@ -715,23 +717,23 @@ namespace DCFApixels.DragonECS.Unity.Editors
return DrawTypeMetaBlockPadding * 2 + contentHeight; 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); 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); 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); var result = DrawTypeMetaBlock_Internal(ref rect, rootProperty, meta, index, total);
if (result.HasFlag(DrawTypeMetaBlockResultFlags.CloseButtonClicked)) if (result.flags.HasFlag(DrawTypeMetaBlockResultFlags.CloseButtonClicked))
{ {
rootProperty.ResetValues(); rootProperty.ResetValues();
} }
return result.HasFlag(DrawTypeMetaBlockResultFlags.DropExpanded); return (result.flags.HasFlag(DrawTypeMetaBlockResultFlags.DropExpanded), result.optionsWidth);
} }
[Flags] [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) if (meta == null)
{ {
EditorGUI.DrawRect(rect, Color.black.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA)); EditorGUI.DrawRect(rect, Color.black.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA));
return DrawTypeMetaBlockResultFlags.None; return (DrawTypeMetaBlockResultFlags.None, 0f);
} }
//string name = meta.Name; //string name = meta.Name;
@ -772,6 +774,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
EditorGUI.DrawRect(rect, panelColor); EditorGUI.DrawRect(rect, panelColor);
float optionsWidth = 0f;
Rect optionRect = rect; Rect optionRect = rect;
rect = rect.AddPadding(DrawTypeMetaBlockPadding * 2f); rect = rect.AddPadding(DrawTypeMetaBlockPadding * 2f);
@ -781,38 +784,45 @@ namespace DCFApixels.DragonECS.Unity.Editors
optionRect.xMin = optionRect.xMax - 64; optionRect.xMin = optionRect.xMax - 64;
optionRect.center += Vector2.up * DrawTypeMetaBlockPadding; optionRect.center += Vector2.up * DrawTypeMetaBlockPadding;
DrawTypeMetaBlockResultFlags result = DrawTypeMetaBlockResultFlags.None; DrawTypeMetaBlockResultFlags result = DrawTypeMetaBlockResultFlags.None;
using (CheckChanged()) using (CheckChanged())
{ {
//Canceling isExpanded //Canceling isExpanded
bool oldIsExpanded = rootProperty.isExpanded; //bool oldIsExpanded = rootProperty.isExpanded;
if (ClickTest(optionRect)) //if (ClickTest(optionRect))
{ //{
rootProperty.isExpanded = oldIsExpanded; // rootProperty.isExpanded = oldIsExpanded;
result |= DrawTypeMetaBlockResultFlags.DropExpanded; // result |= DrawTypeMetaBlockResultFlags.DropExpanded;
} //}
//Close button //Close button
optionRect.xMin = optionRect.xMax - HeadIconsRect.width; optionRect.xMin = optionRect.xMax - HeadIconsRect.width;
optionsWidth += optionRect.width;
if (CloseButton(optionRect)) if (CloseButton(optionRect))
{ {
result |= DrawTypeMetaBlockResultFlags.CloseButtonClicked; result |= DrawTypeMetaBlockResultFlags.CloseButtonClicked;
return result; return (result, optionsWidth);
} }
//Edit script button //Edit script button
if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script)) if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script))
{ {
optionRect = HeadIconsRect.MoveTo(optionRect.center - (Vector2.right * optionRect.width)); optionRect = HeadIconsRect.MoveTo(optionRect.center - (Vector2.right * optionRect.width));
optionsWidth += optionRect.width;
ScriptAssetButton(optionRect, script); ScriptAssetButton(optionRect, script);
} }
//Description icon //Description icon
if (string.IsNullOrEmpty(description) == false) if (string.IsNullOrEmpty(description) == false)
{ {
optionRect = HeadIconsRect.MoveTo(optionRect.center - (Vector2.right * optionRect.width)); optionRect = HeadIconsRect.MoveTo(optionRect.center - (Vector2.right * optionRect.width));
optionsWidth += optionRect.width;
DescriptionIcon(optionRect, description); DescriptionIcon(optionRect, description);
} }
} }
return result; return (result, optionsWidth);
} }
#endregion #endregion
@ -978,11 +988,11 @@ namespace DCFApixels.DragonECS.Unity.Editors
#region Init #region Init
private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes, Type[] sortedWithOutTypes) 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 = new ReferenceDropDown(predicatTypes, sortedWithOutTypes);
menu.OnSelected += SelectComponent; menu.OnSelected += SelectComponent;
_predicatTypesMenus.Add((predicatTypes, sortedWithOutTypes), menu); _predicatTypesMenus.Add(new PredicateTypesKey(predicatTypes[0], predicatTypes, sortedWithOutTypes), menu);
} }
return menu; return menu;

View File

@ -17,6 +17,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
using System.Reflection; using System.Reflection;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.UIElements;
using UnityObject = UnityEngine.Object; using UnityObject = UnityEngine.Object;
@ -213,21 +214,30 @@ namespace DCFApixels.DragonECS.Unity.Editors
_isStaticInit = true; _isStaticInit = true;
OnStaticInit(); OnStaticInit();
} }
public void Init() public void Init(SerializedProperty property)
{ {
if (IsInit) { return; } if (IsInit) { return; }
_isInit = true; _isInit = true;
OnInit(); OnInit(property);
} }
protected virtual void OnStaticInit() { } 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) public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{ {
using (EcsGUI.CheckChanged(property.serializedObject)) using (EcsGUI.CheckChanged(property.serializedObject))
{ {
StaticInit(); StaticInit();
Init(); Init(property);
DrawCustom(position, property, label); DrawCustom(position, property, label);
} }
} }

View File

@ -86,93 +86,94 @@ namespace DCFApixels.DragonECS.Unity.Editors
} }
} }
} }
internal class ComponentTemplatesDropDown : MetaObjectsDropDown<ComponentTemplateTypeCache> //internal class ComponentTemplatesDropDown : MetaObjectsDropDown<ComponentTemplateTypeCache>
{ //{
private ComponentTemplatesDropDown() { } // private ComponentTemplatesDropDown() { }
//
private bool _isCheckUnique; // private bool _isCheckUnique;
private SerializedProperty _arrayProperty; // private SerializedProperty _arrayProperty;
private SerializedProperty _fieldProperty; // private SerializedProperty _fieldProperty;
//
public static Dictionary<PredicateTypesKey, ComponentTemplatesDropDown> _dropDownsCache = new Dictionary<PredicateTypesKey, ComponentTemplatesDropDown>(32); // public static Dictionary<PredicateTypesKey, ComponentTemplatesDropDown> _dropDownsCache = new Dictionary<PredicateTypesKey, ComponentTemplatesDropDown>(32);
public static ComponentTemplatesDropDown Get(PredicateTypesKey key) // public static ComponentTemplatesDropDown Get(PredicateTypesKey key)
{ // {
if(_dropDownsCache.TryGetValue(key, out var result) == false) // if(_dropDownsCache.TryGetValue(key, out var result) == false)
{ // {
result = new ComponentTemplatesDropDown(); // result = new ComponentTemplatesDropDown();
IEnumerable<(ComponentTemplateTypeCache template, ITypeMeta meta)> itemMetaPairs = ComponentTemplateTypeCache.All.ToArray() // IEnumerable<(ComponentTemplateTypeCache template, ITypeMeta meta)> itemMetaPairs = ComponentTemplateTypeCache.All.ToArray()
.Where(o => // .Where(o =>
{ // {
return key.Check(o.Type); // return key.Check(o.Type);
}) // })
.Select(o => // .Select(o =>
{ // {
return (o, o.Meta); // return (o, o.Meta);
}); // });
//TODO оптимизировать или вырезать //
itemMetaPairs = itemMetaPairs.OrderBy(o => o.meta.Group.Name); // //TODO оптимизировать или вырезать
result.Setup(itemMetaPairs); // itemMetaPairs = itemMetaPairs.OrderBy(o => o.meta.Group.Name);
_dropDownsCache[key] = result; // result.Setup(itemMetaPairs);
} // _dropDownsCache[key] = result;
return result; // }
} // return result;
// }
public void OpenForArray(Rect position, SerializedProperty arrayProperty, bool isCheckUnique) //
{ // public void OpenForArray(Rect position, SerializedProperty arrayProperty, bool isCheckUnique)
_isCheckUnique = isCheckUnique; // {
_arrayProperty = arrayProperty; // _isCheckUnique = isCheckUnique;
_fieldProperty = null; // _arrayProperty = arrayProperty;
Show(position); // _fieldProperty = null;
} // Show(position);
public void OpenForField(Rect position, SerializedProperty fieldProperty) // }
{ // public void OpenForField(Rect position, SerializedProperty fieldProperty)
_isCheckUnique = false; // {
_arrayProperty = null; // _isCheckUnique = false;
_fieldProperty = fieldProperty; // _arrayProperty = null;
Show(position); // _fieldProperty = fieldProperty;
} // Show(position);
// }
protected override void ItemSelected(Item item) //
{ // protected override void ItemSelected(Item item)
base.ItemSelected(item); // {
// base.ItemSelected(item);
if (item.Obj == null) //
{ // if (item.Obj == null)
_fieldProperty.managedReferenceValue = null; // {
_fieldProperty.serializedObject.ApplyModifiedProperties(); // _fieldProperty.managedReferenceValue = null;
return; // _fieldProperty.serializedObject.ApplyModifiedProperties();
} // return;
// }
Type componentType = item.Obj.GetType(); //
var data = item.Obj; // Type componentType = item.Obj.GetType();
// var data = item.Obj;
if (_arrayProperty != null && data != null) //
{ // if (_arrayProperty != null && data != null)
int index = _arrayProperty.arraySize; // {
if (_isCheckUnique) // int index = _arrayProperty.arraySize;
{ // if (_isCheckUnique)
if (data.IsUnique) // {
{ // if (data.IsUnique)
for (int i = 0, iMax = _arrayProperty.arraySize; i < iMax; i++) // {
{ // for (int i = 0, iMax = _arrayProperty.arraySize; i < iMax; i++)
if (_arrayProperty.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType) // {
{ // if (_arrayProperty.GetArrayElementAtIndex(i).managedReferenceValue.GetType() == componentType)
return; // {
} // return;
} // }
} // }
} // }
_arrayProperty.arraySize += 1; // }
_fieldProperty = _arrayProperty.GetArrayElementAtIndex(index); // _arrayProperty.arraySize += 1;
} // _fieldProperty = _arrayProperty.GetArrayElementAtIndex(index);
// }
if (_fieldProperty != null) //
{ // if (_fieldProperty != null)
_fieldProperty.managedReferenceValue = data.CreateInstance(); // {
_fieldProperty.serializedObject.ApplyModifiedProperties(); // _fieldProperty.managedReferenceValue = data.CreateInstance();
} // _fieldProperty.serializedObject.ApplyModifiedProperties();
} // }
} // }
//}
internal class RuntimeComponentsDropDown : MetaObjectsDropDown<IEcsPool> internal class RuntimeComponentsDropDown : MetaObjectsDropDown<IEcsPool>
{ {
public RuntimeComponentsDropDown(IEnumerable<IEcsPool> pools) public RuntimeComponentsDropDown(IEnumerable<IEcsPool> pools)
@ -215,6 +216,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
private bool _isContainsNull; private bool _isContainsNull;
public IEnumerable<(T, ITypeMeta)> _itemMetaPairs; public IEnumerable<(T, ITypeMeta)> _itemMetaPairs;
public virtual bool IsStaticList { get { return true; } }
public MetaObjectsDropDown() : base(new AdvancedDropdownState()) public MetaObjectsDropDown() : base(new AdvancedDropdownState())
{ {
minimumSize = new Vector2(220f, EditorGUIUtility.singleLineHeight * 20); minimumSize = new Vector2(220f, EditorGUIUtility.singleLineHeight * 20);
@ -225,6 +227,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
_name = name; _name = name;
_isContainsNull = isContainsNull; _isContainsNull = isContainsNull;
_itemMetaPairs = itemMetaPairs; _itemMetaPairs = itemMetaPairs;
if (IsStaticList)
{
_itemMetaPairs = _itemMetaPairs.ToArray();
}
} }
protected override AdvancedDropdownItem BuildRoot() protected override AdvancedDropdownItem BuildRoot()
{ {
@ -235,10 +241,9 @@ namespace DCFApixels.DragonECS.Unity.Editors
{ {
root.AddChild(new Item(default, "<NULL>", increment++)); root.AddChild(new Item(default, "<NULL>", increment++));
} }
Dictionary<Key, Item> dict = new Dictionary<Key, Item>(); Dictionary<Key, Item> dict = new Dictionary<Key, Item>();
var list = _itemMetaPairs.ToArray();
foreach (var pair in _itemMetaPairs) foreach (var pair in _itemMetaPairs)
{ {
ITypeMeta meta = pair.Item2; ITypeMeta meta = pair.Item2;

View File

@ -1,117 +1,109 @@
using System; //using System;
//
namespace DCFApixels.DragonECS.Unity.Editors //#if UNITY_EDITOR
{ //namespace DCFApixels.DragonECS.Unity.Internal
internal interface IReferenceButtonAttribute //{
{ // using DCFApixels.DragonECS.Unity.Editors;
Type[] PredicateTypes { get; } // using UnityEditor;
bool IsHideButtonIfNotNull { get; } // internal partial class UnityReflectionCache
} // {
} // public bool IsReferenceButtonCacheInit_Editor;
// public bool InitReferenceButtonCache_Editor(SerializedProperty sp)
#if UNITY_EDITOR // {
namespace DCFApixels.DragonECS.Unity.Internal // if (IsReferenceButtonCacheInit_Editor) { return false; }
{ //
using DCFApixels.DragonECS.Unity.Editors; // HasSerializableData_Editor = sp.HasSerializableData();
using UnityEditor; //
internal partial class UnityReflectionCache // IsReferenceButtonCacheInit_Editor = true;
{ // return true;
public bool IsReferenceButtonCacheInit_Editor; // }
public bool InitReferenceButtonCache_Editor(SerializedProperty sp) // public bool HasSerializableData_Editor;
{ // }
if (IsReferenceButtonCacheInit_Editor) { return false; } //}
//
HasSerializableData_Editor = sp.HasSerializableData(); //namespace DCFApixels.DragonECS.Unity.Editors
//{
IsReferenceButtonCacheInit_Editor = true; // using DCFApixels.DragonECS.Unity.Internal;
return true; // using System;
} // using UnityEditor;
public bool HasSerializableData_Editor; // using UnityEngine;
} //
} // [CustomPropertyDrawer(typeof(ReferenceButtonAttribute), true)]
// internal sealed class ReferenceButtonAttributeDrawer : ExtendedPropertyDrawer<IReferenceButtonAttribute>
namespace DCFApixels.DragonECS.Unity.Editors // {
{ // private Type[] _withOutTypes;
using DCFApixels.DragonECS.Unity.Internal; //
using System; // protected override void OnInit(SerializedProperty property)
using UnityEditor; // {
using UnityEngine; // Type fieldType = fieldInfo.FieldType;
// _withOutTypes = fieldType.TryGetAttribute(out ReferenceButtonWithOutAttribute a) ? a.PredicateTypes : Array.Empty<Type>();
[CustomPropertyDrawer(typeof(ReferenceButtonAttribute), true)] // //if (fieldType.IsGenericType)
internal sealed class ReferenceButtonAttributeDrawer : ExtendedPropertyDrawer<IReferenceButtonAttribute> // //{
{ // // if (fieldType.IsGenericTypeDefinition == false)
private Type[] _withOutTypes; // // {
protected override void OnInit() // // fieldType = fieldType.GetGenericTypeDefinition();
{ // // }
Type fieldType = fieldInfo.FieldType; // //}
_withOutTypes = fieldType.TryGetAttribute(out ReferenceButtonWithOutAttribute a) ? a.PredicateTypes : Array.Empty<Type>(); // }
//if (fieldType.IsGenericType) //
//{ // private UnityReflectionCache _reflectionCache;
// if (fieldType.IsGenericTypeDefinition == false) // private UnityReflectionCache Cahce(SerializedProperty sp)
// { // {
// fieldType = fieldType.GetGenericTypeDefinition(); // if (UnityReflectionCache.InitLocal(sp.managedReferenceValue.GetType(), ref _reflectionCache))
// } // {
//} // _reflectionCache.InitReferenceButtonCache_Editor(sp);
} // }
// return _reflectionCache;
private UnityReflectionCache _reflectionCache; // }
private UnityReflectionCache Cahce(SerializedProperty sp) //
{ // public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
if (UnityReflectionCache.InitLocal(sp.managedReferenceValue.GetType(), ref _reflectionCache)) // {
{ // Init(property);
_reflectionCache.InitReferenceButtonCache_Editor(sp); // if (property.propertyType == SerializedPropertyType.ManagedReference &&
} // property.managedReferenceValue != null &&
return _reflectionCache; // Cahce(property).HasSerializableData_Editor)
} // {
// return EditorGUI.GetPropertyHeight(property, label, true);
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) // }
{ // else
Init(); // {
if (property.propertyType == SerializedPropertyType.ManagedReference && // return OneLineHeight;
property.managedReferenceValue != null && // }
Cahce(property).HasSerializableData_Editor) // }
{ //
return EditorGUI.GetPropertyHeight(property, label, true); // protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label)
} // {
else // if(property.propertyType != SerializedPropertyType.ManagedReference)
{ // {
return OneLineHeight; // GUI.Label(position, label);
} // return;
} // }
// if (IsArrayElement)
protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) // {
{ // label = UnityEditorUtility.GetLabelTemp();
if(property.propertyType != SerializedPropertyType.ManagedReference) // }
{ // Rect selButtnoRect = position;
GUI.Label(position, label); // selButtnoRect.height = OneLineHeight;
return; // DrawSelectionPopupButton(selButtnoRect, property);
} //
if (IsArrayElement) // if (property.managedReferenceValue != null &&
{ // Cahce(property).HasSerializableData_Editor)
label = UnityEditorUtility.GetLabelTemp(); // {
} // EditorGUI.PropertyField(position, property, label, true);
Rect selButtnoRect = position; // }
selButtnoRect.height = OneLineHeight; // else
DrawSelectionPopupButton(selButtnoRect, property); // {
// EditorGUI.BeginProperty(position, label, property);
if (property.managedReferenceValue != null && // EditorGUI.LabelField(position, label);
Cahce(property).HasSerializableData_Editor) // EditorGUI.EndProperty();
{ // }
EditorGUI.PropertyField(position, property, label, true); // }
} //
else // private void DrawSelectionPopupButton(Rect position, SerializedProperty property)
{ // {
EditorGUI.BeginProperty(position, label, property); // Rect buttonRect = IsArrayElement ? position : position.AddPadding(EditorGUIUtility.labelWidth, 0f, 0f, 0f); ;
EditorGUI.LabelField(position, label); // EcsGUI.DrawSelectReferenceButton(buttonRect, property, Attribute.PredicateTypes.Length == 0 ? new Type[1] { fieldInfo.FieldType } : Attribute.PredicateTypes, _withOutTypes, Attribute.IsHideButtonIfNotNull);
EditorGUI.EndProperty(); // }
} // }
} //}
//#endif
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

View File

@ -105,10 +105,6 @@ namespace DCFApixels.DragonECS.Unity.Internal
} }
return _memberwiseCloneMethdo.Invoke(obj, null); return _memberwiseCloneMethdo.Invoke(obj, null);
} }
internal static object Clone_Reflection<T>(this T obj)
{
return Clone_Reflection((object)obj);
}
} }
internal partial class UnityReflectionCache internal partial class UnityReflectionCache

View File

@ -1,24 +1,30 @@
using System; using System;
using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Internal namespace DCFApixels.DragonECS.Unity.Internal
{ {
internal readonly struct PredicateTypesKey : IEquatable<PredicateTypesKey> internal readonly struct PredicateTypesKey : IEquatable<PredicateTypesKey>
{ {
public readonly Type[] Types; public readonly Type TargetType;
public readonly Type[] AllowTypes;
public readonly Type[] WithoutTypes; public readonly Type[] WithoutTypes;
public PredicateTypesKey(Type[] types) : this(types, Type.EmptyTypes) { } public PredicateTypesKey(Type signleType) : this(signleType, new Type[] { signleType } , Type.EmptyTypes) { }
public PredicateTypesKey(Type[] types, Type[] withoutTypes) 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; WithoutTypes = withoutTypes;
} }
public bool Check(Type type) public bool Check(Type type)
{ {
bool isAssignable = false; bool isAssignable = AllowTypes.Length == 0;
foreach (Type predicateTypes in Types) foreach (Type allowType in AllowTypes)
{ {
if (predicateTypes.IsAssignableFrom(type)) if (allowType.IsAssignableFrom(type))
{ {
isAssignable = true; isAssignable = true;
break; break;
@ -37,15 +43,20 @@ namespace DCFApixels.DragonECS.Unity.Internal
} }
} }
return isAssignable; return isAssignable && TargetType.IsAssignableFrom(type);
} }
public bool Equals(PredicateTypesKey other) 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; } 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; return false;
} }
@ -65,8 +76,7 @@ namespace DCFApixels.DragonECS.Unity.Internal
} }
public override int GetHashCode() 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); }
} }
} }

View File

@ -8,6 +8,10 @@ namespace DCFApixels.DragonECS.Unity.Internal
{ {
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
internal static void ArgumentNullException()
{
throw new ArgumentNullException();
}
internal static void Argument(string message) internal static void Argument(string message)
{ {
throw new ArgumentException(message); throw new ArgumentException(message);

View File

@ -12,7 +12,10 @@ namespace DCFApixels.DragonECS
public struct ComponentTemplateProperty : IEquatable<ComponentTemplateProperty> public struct ComponentTemplateProperty : IEquatable<ComponentTemplateProperty>
{ {
[SerializeReference] [SerializeReference]
[ReferenceDropDown]
[TypeMetaBlock]
private ITemplateNode _template; private ITemplateNode _template;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ComponentTemplateProperty(ITemplateNode template) public ComponentTemplateProperty(ITemplateNode template)
{ {
@ -28,7 +31,7 @@ namespace DCFApixels.DragonECS
public Type Type public Type Type
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 public bool IsNull
{ {
@ -83,12 +86,19 @@ namespace DCFApixels.DragonECS
public readonly struct Null { } public readonly struct Null { }
} }
public sealed class ComponentTemplateFieldAttribute : PropertyAttribute, IReferenceButtonAttribute public sealed class ComponentTemplateFieldAttribute : PropertyAttribute, IReferenceDropDownAttribute
{ {
public Type[] PredicateTypes; public Type[] PredicateTypes;
Type[] IReferenceButtonAttribute.PredicateTypes { get { return PredicateTypes; } } public readonly bool IsHideButtonIfNotNull = true;
bool IReferenceButtonAttribute.IsHideButtonIfNotNull { get { return true; } } Type[] IReferenceDropDownAttribute.PredicateTypes { get { return PredicateTypes; } }
public ComponentTemplateFieldAttribute() { } bool IReferenceDropDownAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } }
public ComponentTemplateFieldAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty<Type>()) { }
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 { }
} }

View File

@ -9,200 +9,222 @@ namespace DCFApixels.DragonECS.Unity.Editors
[CustomPropertyDrawer(typeof(ComponentTemplateProperty), true)] [CustomPropertyDrawer(typeof(ComponentTemplateProperty), true)]
internal class ComponentTemplatePropertyDrawer : ExtendedPropertyDrawer internal class ComponentTemplatePropertyDrawer : ExtendedPropertyDrawer
{ {
private ComponentTemplateReferenceDrawer _drawer = new ComponentTemplateReferenceDrawer(new PredicateTypesKey(new Type[] { typeof(ITemplateNode) })); //private EcsDragonFieldDrawer _drawer = new EcsDragonFieldDrawer(new PredicateTypesKey(typeof(ITemplateNode)));
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) //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); property.Next(true);
_drawer.StaticInit(); return EditorGUI.GetPropertyHeight(property, label);
_drawer.Init();
return _drawer.GetPropertyHeight(property, label);
} }
protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label)
{ {
var root = property.Copy(); var root = property.Copy();
property.Next(true); property.Next(true);
_drawer.StaticInit(); EditorGUI.PropertyField(position, property, label);
_drawer.Init();
_drawer.Draw(position, root, property, label);
}
}
[CustomPropertyDrawer(typeof(ComponentTemplateFieldAttribute), true)]
internal class ComponentTemplateReferenceDrawer : ExtendedPropertyDrawer<ComponentTemplateFieldAttribute>
{
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<Type>();
}
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);
} }
} }
//[CustomPropertyDrawer(typeof(ComponentTemplateFieldAttribute), true)]
//internal class ComponentTemplateFieldDrawer : ExtendedPropertyDrawer<ComponentTemplateFieldAttribute>
//{
// 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<Type>();
// }
// 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 #endif

View File

@ -10,13 +10,14 @@ namespace DCFApixels.DragonECS.Unity.Editors
{ {
internal abstract class EntityTemplateEditorBase : ExtendedEditor internal abstract class EntityTemplateEditorBase : ExtendedEditor
{ {
private ComponentTemplatesDropDown _componentDropDown; private DragonFieldDropDown _componentDropDown;
private SerializedProperty _componentsProp; private SerializedProperty _componentTemplatesProp;
private SerializedProperty _templatesProp;
private ReorderableList _reorderableComponentsList; private ReorderableList _reorderableComponentsList;
private int _reorderableComponentsListLastCount; 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; } protected abstract bool IsSO { get; }
@ -24,11 +25,12 @@ namespace DCFApixels.DragonECS.Unity.Editors
protected override bool IsInit { get { return _componentDropDown != null; } } protected override bool IsInit { get { return _componentDropDown != null; } }
protected override void OnInit() 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.onAddCallback += OnReorderableComponentsListAdd;
_reorderableComponentsList.onRemoveCallback += OnReorderableListRemove; _reorderableComponentsList.onRemoveCallback += OnReorderableListRemove;
_reorderableComponentsList.drawElementCallback += OnReorderableListDrawEmptyElement; _reorderableComponentsList.drawElementCallback += OnReorderableListDrawEmptyElement;
@ -73,48 +75,67 @@ namespace DCFApixels.DragonECS.Unity.Editors
private float OnReorderableComponentsListElementHeight(int index) private float OnReorderableComponentsListElementHeight(int index)
{ {
var componentProperty = GetTargetProperty(_componentsProp.GetArrayElementAtIndex(index)); SerializedProperty prop = _componentTemplatesProp.GetArrayElementAtIndex(index);
float result = EditorGUI.GetPropertyHeight(componentProperty); GUIContent label = UnityEditorUtility.GetLabelTemp();
return EcsGUI.GetTypeMetaBlockHeight(result) + Spacing * 2f; 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) 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); rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing);
using (EcsGUI.CheckChanged())
{
SerializedProperty prop = _componentsProp.GetArrayElementAtIndex(index);
IComponentTemplate template = prop.managedReferenceValue as IComponentTemplate; EditorGUI.PropertyField(rect, prop, label);
if (template == null || prop.managedReferenceValue == null) return;
{ //if (index < 0 || Event.current.type == EventType.Used) { return; }
//DrawDamagedComponent_Replaced(prop, index); //rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing);
EditorGUI.PropertyField(rect, prop, UnityEditorUtility.GetLabel(prop.displayName), true); //using (EcsGUI.CheckChanged())
return; //{
} // SerializedProperty prop = _componentTemplatesProp.GetArrayElementAtIndex(index);
//
var componentProp = GetTargetProperty(prop); // var template = prop.managedReferenceValue;
// if (template == null)
// {
ITypeMeta meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.GetMeta(); // //DrawDamagedComponent_Replaced(prop, index);
// EditorGUI.PropertyField(rect, prop, UnityEditorUtility.GetLabel(prop.displayName), true);
if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _componentsProp, index, componentProp, meta)) // return;
{ // }
return; // IComponentTemplate componentTemplate = template as IComponentTemplate;
} // var componentProp = GetTargetProperty(prop);
//
// ITypeMeta meta = template as ITypeMeta;
GUIContent label = UnityEditorUtility.GetLabel(meta.Name); // if(meta == null)
if (componentProp.propertyType == SerializedPropertyType.Generic) // {
{ // if (componentTemplate != null)
EditorGUI.PropertyField(rect, componentProp, label, true); // {
} // meta = componentTemplate.ComponentType.GetMeta();
else // }
{ // else
EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true); // {
} // 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) private void OnReorderableComponentsListAdd(ReorderableList list)
@ -147,6 +168,8 @@ namespace DCFApixels.DragonECS.Unity.Editors
{ {
Init(); Init();
if (IsSO) if (IsSO)
{ {
EcsGUI.Layout.ManuallySerializeButton(targets); EcsGUI.Layout.ManuallySerializeButton(targets);
@ -186,21 +209,32 @@ namespace DCFApixels.DragonECS.Unity.Editors
SerializedProperty iterator = serializedObject.GetIterator(); SerializedProperty iterator = serializedObject.GetIterator();
iterator.NextVisible(true); iterator.NextVisible(true);
using (EcsGUI.Disable)
{
EditorGUILayout.PropertyField(iterator, true);
}
while (iterator.NextVisible(false)) 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 else
{ {
EditorGUILayout.PropertyField(iterator, true); 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) private void DrawTop(SerializedProperty componentsProp)
{ {

View File

@ -4,6 +4,7 @@
using DCFApixels.DragonECS.Unity.Internal; using DCFApixels.DragonECS.Unity.Internal;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
@ -14,7 +15,7 @@ namespace DCFApixels.DragonECS
public interface IComponentTemplate : ITemplateNode public interface IComponentTemplate : ITemplateNode
{ {
#region Properties #region Properties
Type Type { get; } Type ComponentType { get; }
bool IsUnique { get; } bool IsUnique { get; }
#endregion #endregion
@ -33,16 +34,11 @@ namespace DCFApixels.DragonECS
} }
[Serializable] [Serializable]
public abstract class ComponentTemplateBase : IComponentTemplate, ITypeMeta [MetaProxy(typeof(ComponentTemplateMetaProxy))]
public abstract class ComponentTemplateBase : IComponentTemplate
{ {
#region Properties #region Properties
public abstract Type Type { get; } public abstract Type ComponentType { 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<string> Tags { get { return Array.Empty<string>(); } }
public virtual bool IsUnique { get { return true; } } public virtual bool IsUnique { get { return true; } }
#endregion #endregion
@ -54,67 +50,136 @@ namespace DCFApixels.DragonECS
public abstract void Apply(short worldID, int entityID); public abstract void Apply(short worldID, int entityID);
#endregion #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<string> 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] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public abstract class ComponentTemplateBase<T> : ComponentTemplateBase, ICloneable public abstract class ComponentTemplateBase<T> : ComponentTemplateBase, ICloneable
where T : struct
{ {
protected static readonly TypeMeta Meta = EcsDebugUtility.GetTypeMeta<T>(); protected static readonly TypeMeta Meta = EcsDebugUtility.GetTypeMeta<T>();
private static bool _defaultValueTypeInit = false; private static bool _defaultValueInit = false;
private static T _defaultValueType; private static bool _hasDefaultValue = false;
protected static T DefaultValueType 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 get
{ {
if (_defaultValueTypeInit == false) if (_hasDefaultValue)
{ {
Type type = typeof(T); return CloneComponent(_defaultValue);
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 _defaultValueType; return default;
} }
} }
[SerializeField] [SerializeField]
protected T component = DefaultValueType; protected T component;
[SerializeField] [SerializeField]
[HideInInspector] [HideInInspector]
private byte _offset; // Avoids the error "Cannot get managed reference index with out bounds offset" private byte _offset; // Avoids the error "Cannot get managed reference index with out bounds offset"
#region Properties public ComponentTemplateBase()
public sealed override ITypeMeta BaseMeta { get { return Meta; } } {
public sealed override Type Type { get { return typeof(T); } } InitStatic();
public override string Name { get { return Meta.Name; } } component = DefaultComponent;
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 sealed override Type ComponentType { get { return typeof(T); } }
public override IReadOnlyList<string> Tags { get { return Meta.Tags; } }
#endregion
#region Methods #region Methods
public sealed override object GetRaw() { return component; } public sealed override object GetRaw() { return component; }
public sealed override void SetRaw(object raw) { component = (T)raw; } 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() object ICloneable.Clone()
{ {
ComponentTemplateBase<T> templateClone = (ComponentTemplateBase<T>)MemberwiseClone(); ComponentTemplateBase<T> templateClone = (ComponentTemplateBase<T>)MemberwiseClone();
templateClone.component = CloneComponent(); templateClone.component = CloneComponent(component);
return templateClone; return templateClone;
} }
#endregion #endregion
@ -175,7 +240,9 @@ namespace DCFApixels.DragonECS.Unity.Editors
{ {
if (_meta == null) if (_meta == null)
{ {
_meta = ComponentType.GetMeta(); {
_meta = ComponentType.GetMeta();
}
} }
return _meta; return _meta;
} }
@ -194,7 +261,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
field = Type.GetField("Default", BindingFlags.Static | BindingFlags.Public); field = Type.GetField("Default", BindingFlags.Static | BindingFlags.Public);
if (field != null && field.FieldType == Type) if (field != null && field.FieldType == Type)
{ {
_defaultValueDummy = field.GetValue(null); _defaultValueDummy = field.GetValue(null).Clone_Reflection();
} }
if(_defaultValueDummy == null) if(_defaultValueDummy == null)
@ -202,7 +269,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
field = Type.GetField("Empty", BindingFlags.Static | BindingFlags.Public); field = Type.GetField("Empty", BindingFlags.Static | BindingFlags.Public);
if (field != null && field.FieldType == Type) 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; Type = type;
IsUnique = false; 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); var ct = (IComponentTemplate)Activator.CreateInstance(type);
IsUnique = ct.IsUnique; IsUnique = ct.IsUnique;
ComponentType = ct.Type; ComponentType = ct.ComponentType;
if (ct is ITypeMeta metaOverride)
{
_meta = metaOverride;
}
} }
else else
{ {

View File

@ -2,6 +2,7 @@
#undef DEBUG #undef DEBUG
#endif #endif
using DCFApixels.DragonECS.Unity; using DCFApixels.DragonECS.Unity;
using DCFApixels.DragonECS.Unity.Internal;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -24,8 +25,10 @@ namespace DCFApixels.DragonECS
public class MonoEntityTemplate : MonoEntityTemplateBase, ITemplateNode public class MonoEntityTemplate : MonoEntityTemplateBase, ITemplateNode
{ {
[SerializeReference] [SerializeReference]
[ReferenceButton(true, typeof(ITemplateNode))] [ReferenceDropDown(true)]
[TypeMetaBlock]
[FormerlySerializedAs("_components")] [FormerlySerializedAs("_components")]
[ArrayElement]
private ITemplateNode[] _componentTemplates; private ITemplateNode[] _componentTemplates;
#region Methods #region Methods

View File

@ -25,7 +25,7 @@ namespace DCFApixels.DragonECS
[SerializeField] [SerializeField]
private ScriptableEntityTemplateBase[] _templates; private ScriptableEntityTemplateBase[] _templates;
[SerializeReference] [SerializeReference]
[ReferenceButton(true, typeof(ITemplateNode))] [ReferenceDropDown(true)]
[FormerlySerializedAs("_components")] [FormerlySerializedAs("_components")]
private ITemplateNode[] _componentTemplates; private ITemplateNode[] _componentTemplates;

View File

@ -119,7 +119,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
bool isNull = targetProp.managedReferenceValue == null; bool isNull = targetProp.managedReferenceValue == null;
ITypeMeta meta = isNull ? null : targetProp.managedReferenceValue.GetMeta(); 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; return;
} }

View File

@ -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; float result = 0f;
if (IsArrayElement == false) if (IsArrayElement == false)

View File

@ -103,8 +103,8 @@ namespace DCFApixels.DragonECS.Unity
public struct Record public struct Record
{ {
[SerializeReference] [SerializeReference]
[ReferenceButton(true, typeof(IEcsModule), typeof(IEcsProcess))] [ReferenceDropDown(true, typeof(IEcsModule), typeof(IEcsProcess))]
[ReferenceButtonWithOut(typeof(IEcsRunner))] [ReferenceDropDownWithout(typeof(IEcsRunner))]
[ArrayElement] [ArrayElement]
public object target;// нельзя менять поярдок полей, иначе это поломает отрисовку в инспекторе изза применения property.Next(bool); public object target;// нельзя менять поярдок полей, иначе это поломает отрисовку в инспекторе изза применения property.Next(bool);
public AddParams parameters; public AddParams parameters;

View File

@ -2,35 +2,637 @@
#undef DEBUG #undef DEBUG
#endif #endif
using DCFApixels.DragonECS.Unity.Editors; using DCFApixels.DragonECS.Unity.Editors;
using DCFApixels.DragonECS.Unity.Internal;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine; using UnityEngine;
namespace DCFApixels.DragonECS 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<Type>()) { }
// 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<Type>()) { }
// 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; public readonly bool IsHideButtonIfNotNull;
Type[] IReferenceButtonAttribute.PredicateTypes { get { return PredicateTypes; } } Type[] IReferenceDropDownAttribute.PredicateTypes { get { return AllowTypes; } }
bool IReferenceButtonAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } } bool IReferenceDropDownAttribute.IsHideButtonIfNotNull { get { return IsHideButtonIfNotNull; } }
public ReferenceButtonAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty<Type>()) { } public ReferenceDropDownAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty<Type>()) { }
public ReferenceButtonAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { } public ReferenceDropDownAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { }
public ReferenceButtonAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes) public ReferenceDropDownAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes)
{ {
IsHideButtonIfNotNull = isHideButtonIfNotNull; IsHideButtonIfNotNull = isHideButtonIfNotNull;
PredicateTypes = predicateTypes; AllowTypes = predicateTypes;
Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); 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; public readonly Type[] PredicateTypes;
[Obsolete("With empty parameters, this attribute makes no sense.", true)] [Obsolete("With empty parameters, this attribute makes no sense.", true)]
public ReferenceButtonWithOutAttribute() : this(Array.Empty<Type>()) { } public ReferenceDropDownWithoutAttribute() : this(Array.Empty<Type>()) { }
public ReferenceButtonWithOutAttribute(params Type[] predicateTypes) public ReferenceDropDownWithoutAttribute(params Type[] predicateTypes)
{ {
PredicateTypes = predicateTypes; PredicateTypes = predicateTypes;
Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal));
} }
} }
} 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<DragonFieldCahce>
{
private DragonFieldDropDown() { }
private bool _isCheckUnique;
private SerializedProperty _arrayProperty;
private SerializedProperty _fieldProperty;
public static Dictionary<PredicateTypesKey, DragonFieldDropDown> _dropDownsCache = new Dictionary<PredicateTypesKey, DragonFieldDropDown>(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<DragonFieldCahce> All
{
get { return _all; }
}
static DragonFieldCahce() { StaticInit(); }
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void StaticInit()
{
List<DragonFieldCahce> list = new List<DragonFieldCahce>(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