improve drawing of runtime component and meta block

This commit is contained in:
Mikhail 2026-04-20 15:50:46 +08:00
parent a21811ffc5
commit e863fdc8e6
16 changed files with 605 additions and 303 deletions

View File

@ -42,7 +42,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
using (DragonGUI.SetBackgroundColor(labelBackColor))
{
GUILayout.Box("Is Empty", UnityEditorUtility.GetWhiteStyle(), GUILayout.ExpandWidth(true));
GUILayout.Box("Is Empty", UnityEditorUtility.GetWhiteStyleWithPadding(), GUILayout.ExpandWidth(true));
}
DragonGUI.Layout.DrawWorldBaseInfo(Target.GetCurrentWorldRaw());

View File

@ -27,14 +27,9 @@ namespace DCFApixels.DragonECS.Unity.Editors
private void OnGUI()
{
var prefs = UserSettingsPrefs.instance;
float labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 0f;
//float checkBoxWidth = 20f;
GUILayout.Space(20f);
using (new DragonGUI.ColorScope(Color.white * 0.5f))
GUILayout.BeginVertical(EditorStyles.helpBox);
using (new DragonGUI.ColorScope(Color.white * 0.5f)) GUILayout.BeginVertical(EditorStyles.helpBox);
//using (new EcsGUI.ColorScope(Color.white * 1.2f))
GUILayout.Label("", EditorStyles.toolbar, GUILayout.ExpandWidth(true), GUILayout.Height(22f));
Rect rect = GUILayoutUtility.GetLastRect();
@ -57,7 +52,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
UnityEditorUtility.TransformFieldName(nameof(UserSettingsPrefs.IsUseCustomNames)),
prefs.IsUseCustomNames);
prefs.ComponentColorMode = (ComponentColorMode)EditorGUILayout.EnumPopup(UnityEditorUtility.TransformFieldName(nameof(UserSettingsPrefs.ComponentColorMode)), prefs.ComponentColorMode);
prefs.RuntimeDrawMode = (RuntimeDrawMode)EditorGUILayout.EnumPopup(UnityEditorUtility.TransformFieldName(nameof(UserSettingsPrefs.RuntimeDrawMode)), prefs.RuntimeDrawMode);
prefs.MetaBlockRectStyle = (MetaBlockRectStyle)EditorGUILayout.EnumPopup(UnityEditorUtility.TransformFieldName(nameof(UserSettingsPrefs.MetaBlockRectStyle)), prefs.MetaBlockRectStyle);
prefs.MetaBlockColorMode = (MetaBlockColorMode)EditorGUILayout.EnumPopup(UnityEditorUtility.TransformFieldName(nameof(UserSettingsPrefs.MetaBlockColorMode)), prefs.MetaBlockColorMode);
GUILayout.EndVertical();
@ -87,8 +85,6 @@ namespace DCFApixels.DragonECS.Unity.Editors
InitDefines();
}
GUILayout.EndVertical();
EditorGUIUtility.labelWidth = labelWidth;
}
}
}

View File

@ -4,7 +4,18 @@ using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Editors
{
internal enum ComponentColorMode
internal enum RuntimeDrawMode
{
Lazy,
Live,
}
internal enum MetaBlockRectStyle
{
Clean,
Edge,
Fill,
}
internal enum MetaBlockColorMode
{
Generic = 0,
Auto = 1,
@ -99,15 +110,45 @@ namespace DCFApixels.DragonECS.Unity.Editors
}
[SerializeField]
private ComponentColorMode _componentColorMode = ComponentColorMode.Auto;
public ComponentColorMode ComponentColorMode
private RuntimeDrawMode _runtimeDrawMode = RuntimeDrawMode.Live;
public RuntimeDrawMode RuntimeDrawMode
{
get => _componentColorMode;
get => _runtimeDrawMode;
set
{
if (_componentColorMode != value)
if (_runtimeDrawMode != value)
{
_componentColorMode = value;
_runtimeDrawMode = value;
AutoSave();
}
}
}
[SerializeField]
private MetaBlockRectStyle _metaBlockRectStyle = MetaBlockRectStyle.Edge;
public MetaBlockRectStyle MetaBlockRectStyle
{
get => _metaBlockRectStyle;
set
{
if (_metaBlockRectStyle != value)
{
_metaBlockRectStyle = value;
AutoSave();
}
}
}
[SerializeField]
private MetaBlockColorMode _metaBlockColorMode = MetaBlockColorMode.Auto;
public MetaBlockColorMode MetaBlockColorMode
{
get => _metaBlockColorMode;
set
{
if (_metaBlockColorMode != value)
{
_metaBlockColorMode = value;
AutoSave();
}
}

View File

@ -8,6 +8,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
[CustomEditor(typeof(EntityMonitor))]
internal class EntityMonitorEditor : ExtendedEditor<EntityMonitor>
{
public override bool RequiresConstantRepaint()
{
return UserSettingsPrefs.instance.RuntimeDrawMode == RuntimeDrawMode.Live ? true : base.RequiresConstantRepaint();
}
protected override void DrawCustom()
{
var entity = Target.Entity;

View File

@ -222,11 +222,18 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
public VerticalScope(GUILayoutOption[] options) { GUILayout.BeginVertical(options); }
public VerticalScope(GUIStyle style, GUILayoutOption[] options) { GUILayout.BeginVertical(style, options); }
public VerticalScope(GUIStyle style, Color backgroundColor, GUILayoutOption[] options)
{
using (SetColor(backgroundColor))
{
GUILayout.BeginVertical(style, options);
}
}
public VerticalScope(Color backgroundColor, GUILayoutOption[] options)
{
using (SetColor(backgroundColor))
{
GUILayout.BeginVertical(UnityEditorUtility.GetWhiteStyle(), options);
GUILayout.BeginVertical(UnityEditorUtility.GetWhiteStyleWithPadding(), options);
}
}
public void Dispose() { GUILayout.EndVertical(); }
@ -239,7 +246,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
using (SetColor(backgroundColor))
{
GUILayout.BeginHorizontal(UnityEditorUtility.GetWhiteStyle(), options);
GUILayout.BeginHorizontal(UnityEditorUtility.GetWhiteStyleWithPadding(), options);
}
}
public void Dispose() { GUILayout.EndHorizontal(); }
@ -262,6 +269,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
public static VerticalScope BeginVertical(params GUILayoutOption[] options) => new VerticalScope(options);
public static VerticalScope BeginVertical(GUIStyle style, params GUILayoutOption[] options) => new VerticalScope(style, options);
public static VerticalScope BeginVertical(Color backgroundColor, params GUILayoutOption[] options) => new VerticalScope(backgroundColor, options);
public static VerticalScope BeginVertical(GUIStyle style, Color backgroundColor, params GUILayoutOption[] options) => new VerticalScope(style, backgroundColor, options);
}
public static CheckChangedScope CheckChanged() => CheckChangedScope.New();
public static CheckChangedScopeWithAutoApply CheckChanged(SerializedObject serializedObject) => new CheckChangedScopeWithAutoApply(serializedObject);
@ -323,10 +331,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
get => EditorGUIUtility.standardVerticalSpacing;
}
private static ComponentColorMode AutoColorMode
private static MetaBlockColorMode MetaBlockColorMode
{
get { return UserSettingsPrefs.instance.ComponentColorMode; }
set { UserSettingsPrefs.instance.ComponentColorMode = value; }
get { return UserSettingsPrefs.instance.MetaBlockColorMode; }
set { UserSettingsPrefs.instance.MetaBlockColorMode = value; }
}
private static bool IsShowHidden
{
@ -784,7 +792,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
if (meta == null)
{
EditorGUI.DrawRect(rect, Color.black.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA));
EditorGUI.DrawRect(rect, Color.black.SetAlpha(EscEditorConsts.MetaBlockFillStyle_Alpha));
return (DrawTypeMetaBlockResultFlags.None, 0f);
}
@ -803,11 +811,34 @@ namespace DCFApixels.DragonECS.Unity.Editors
}
}
Color panelColor = SelectPanelColor(meta, positionIndex, total)
.Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE)
.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA);
EditorGUI.DrawRect(rect, panelColor);
if(Event.current.type == EventType.Repaint)
{
switch (UserSettingsPrefs.instance.MetaBlockRectStyle)
{
default:
case MetaBlockRectStyle.Clean:
{
EditorGUI.DrawRect(rect, Color.white.SetAlpha(EscEditorConsts.MetaBlockCleanStyle_Alpha));
}
break;
case MetaBlockRectStyle.Edge:
{
EditorGUI.DrawRect(rect, Color.white.SetAlpha(EscEditorConsts.MetaBlockCleanStyle_Alpha));
Color panelColor = SelectPanelColor(meta, positionIndex, total)
.SetAlpha(EscEditorConsts.MetaBlockEdgeStyle_Alpha);
EditorGUI.DrawRect(rect.HorizontalGetLeft(4f), panelColor);
}
break;
case MetaBlockRectStyle.Fill:
{
Color panelColor = SelectPanelColor(meta, positionIndex, total)
.Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE)
.SetAlpha(EscEditorConsts.MetaBlockFillStyle_Alpha);
EditorGUI.DrawRect(rect, panelColor);
}
break;
}
}
float optionsWidth = 0f;
Rect optionRect = rect;
@ -926,13 +957,13 @@ namespace DCFApixels.DragonECS.Unity.Editors
}
else
{
switch (AutoColorMode)
switch (MetaBlockColorMode)
{
case ComponentColorMode.Auto:
case MetaBlockColorMode.Auto:
{
return color.ToUnityColor().Desaturate(0.48f) / 1.18f; //.Desaturate(0.48f) / 1.18f;
}
case ComponentColorMode.Rainbow:
case MetaBlockColorMode.Rainbow:
{
int localTotal = Mathf.Max(total, EscEditorConsts.AUTO_COLOR_RAINBOW_MIN_RANGE);
Color hsv = Color.HSVToRGB(1f / localTotal * (index % localTotal), 1, 1);

View File

@ -4,16 +4,16 @@ using System.Collections.Generic;
namespace DCFApixels.DragonECS.Unity.Editors
{
internal class ExpandMatrix
internal class ExpandStack
{
private const bool TOP_DEFAULT = true;
private const bool DEFAULT = false;
private static Dictionary<Type, ExpandMatrix> _instances = new Dictionary<Type, ExpandMatrix>();
public static ExpandMatrix Take(Type type)
private static Dictionary<Type, ExpandStack> _instances = new Dictionary<Type, ExpandStack>();
public static ExpandStack Take(Type type)
{
if (_instances.TryGetValue(type, out ExpandMatrix result) == false)
if (_instances.TryGetValue(type, out ExpandStack result) == false)
{
result = new ExpandMatrix();
result = new ExpandStack();
_instances.Add(type, result);
}
return result;

View File

@ -47,10 +47,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; }
set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; }
}
protected static ComponentColorMode ComponentColorMode
protected static MetaBlockColorMode ComponentColorMode
{
get { return UserSettingsPrefs.instance.ComponentColorMode; }
set { UserSettingsPrefs.instance.ComponentColorMode = value; }
get { return UserSettingsPrefs.instance.MetaBlockColorMode; }
set { UserSettingsPrefs.instance.MetaBlockColorMode = value; }
}
protected bool IsMultipleTargets => targets.Length > 1;
@ -210,10 +210,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; }
set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; }
}
protected static ComponentColorMode ComponentColorMode
protected static MetaBlockColorMode ComponentColorMode
{
get { return UserSettingsPrefs.instance.ComponentColorMode; }
set { UserSettingsPrefs.instance.ComponentColorMode = value; }
get { return UserSettingsPrefs.instance.MetaBlockColorMode; }
set { UserSettingsPrefs.instance.MetaBlockColorMode = value; }
}
protected virtual bool IsStaticInit { get { return _isStaticInit; } }
protected virtual bool IsInit { get { return _isInit; } }

View File

@ -1,4 +1,5 @@
#if UNITY_EDITOR
using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Collections.Generic;
@ -44,10 +45,10 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
#region Properties
private static ComponentColorMode AutoColorMode
private static RuntimeDrawMode RuntimeDrawMode
{
get { return UserSettingsPrefs.instance.ComponentColorMode; }
set { UserSettingsPrefs.instance.ComponentColorMode = value; }
get { return UserSettingsPrefs.instance.RuntimeDrawMode; }
set { UserSettingsPrefs.instance.RuntimeDrawMode = value; }
}
private static bool IsShowHidden
{
@ -65,6 +66,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
internal class RuntimeComponentReflectionCache
{
public readonly Type Type;
public readonly bool IsValueType;
public readonly bool IsUnmanaged;
public readonly DrawerType DrawerType;
public readonly FieldInfoData[] Fields;
@ -74,12 +76,12 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
{
return _wrappers[depth];
}
public RuntimeComponentReflectionCache(Type type)
{
Type = type;
ResetWrappers();
IsUnmanaged = UnsafeUtility.IsUnmanaged(type);
IsValueType = type.IsValueType;
bool isVoideType = type == typeof(void);
bool isUnityObjectType = typeof(UnityObject).IsAssignableFrom(type);
@ -266,7 +268,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
object data = cmp.GetRaw(worldID);
ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType);
ExpandStack expandStack = ExpandStack.Take(componentType);
float padding = EditorGUIUtility.standardVerticalSpacing;
Rect optionButton = GUILayoutUtility.GetLastRect();
@ -277,15 +279,14 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
//Canceling isExpanded
if (DragonGUI.ClickTest(optionButton))
{
ref bool isExpanded = ref expandMatrix.Down();
ref bool isExpanded = ref expandStack.Down();
isExpanded = !isExpanded;
}
Color panelColor = DragonGUI.SelectPanelColor(meta, index, total);
using (DragonGUI.Layout.BeginVertical(panelColor.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA)))
{
EditorGUI.BeginChangeCheck();
using (DragonGUI.Layout.BeginVertical(panelColor.SetAlpha(EscEditorConsts.MetaBlockFillStyle_Alpha)))
{
//Edit script button
if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script))
{
@ -300,7 +301,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
}
RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name);
if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData, 0))
if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandStack, data, out object resultData, 0))
{
cmp.SetRaw(worldID, resultData);
}
@ -355,31 +356,171 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
RuntimeComponentsUtility.GetAddComponentGenericMenu(world).Open(dropDownRect, entityID);
}
using (DragonGUI.SetBackgroundColor(GUI.color.SetAlpha(0.16f)))
using (DragonGUI.Layout.BeginVertical(Color.white.SetAlpha(0.066f)))
{
GUILayout.Box("", UnityEditorUtility.GetWhiteStyle(), GUILayout.ExpandWidth(true));
IsShowHidden = EditorGUILayout.Toggle("Show Hidden", IsShowHidden);
RuntimeDrawMode = (RuntimeDrawMode)EditorGUILayout.EnumPopup("Draw Mode", selected: RuntimeDrawMode);
}
IsShowHidden = EditorGUI.Toggle(GUILayoutUtility.GetLastRect(), "Show Hidden", IsShowHidden);
world.GetComponentPoolsFor(entityID, _componentPoolsBuffer);
for (int i = 0; i < _componentPoolsBuffer.Count; i++)
{
DrawRuntimeComponent(entityID, _componentPoolsBuffer[i], 9, i);
var pool = _componentPoolsBuffer[i];
if (pool.ComponentType.IsValueType)
{
DrawRuntimeValueComponent(entityID, pool, 9, i);
}
else
{
DrawRuntimeClassComponent(entityID, pool, 9, i);
}
}
}
}
}
private void DrawRuntimeComponent(int entityID, IEcsPool pool, int total, int index)
private struct DrawRuntimeCompoentnsCahce : IEcsWorldComponent<DrawRuntimeCompoentnsCahce>
{
var meta = pool.ComponentType.GetMeta();
public EcsWorld World;
public Record[] Records;
void IEcsWorldComponent<DrawRuntimeCompoentnsCahce>.Init(ref DrawRuntimeCompoentnsCahce component, EcsWorld world)
{
component.World = world;
component.Records = new Record[world.Count];
}
void IEcsWorldComponent<DrawRuntimeCompoentnsCahce>.OnDestroy(ref DrawRuntimeCompoentnsCahce component, EcsWorld world) { }
public ref Record GetFor(int componentTypeID)
{
if(componentTypeID >= Records.Length)
{
var newSize = DragonArrayUtility.NextPow2(componentTypeID + 1);
Array.Resize(ref Records, newSize);
}
ref var result = ref Records[componentTypeID];
if(result.IsInit == false && World.TryFindPoolInstance(componentTypeID, out var pool))
{
var componentType = pool.ComponentType;
result.Meta = componentType.GetMeta();
result.ExpandStack = ExpandStack.Take(componentType);
result.FieldInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, result.Meta.Name);
if (ScriptsCache.TryGetScriptAsset(result.Meta, out result.ScriptReference) == false)
{
result.ScriptReference = null;
}
result.IsInit = true;
}
return ref result;
}
public struct Record
{
public bool IsInit;
public TypeMeta Meta;
public ExpandStack ExpandStack;
public RuntimeComponentReflectionCache.FieldInfoData FieldInfoData;
public MonoScript ScriptReference;
}
}
private void DrawRuntimeValueComponent(int entityID, IEcsPool pool, int total, int index)
{
ref var cache = ref pool.World.Get<DrawRuntimeCompoentnsCahce>().GetFor(pool.ComponentTypeID);
var meta = cache.Meta;
if (meta.IsHidden == false || IsShowHidden)
{
Type componentType = pool.ComponentType;
float padding = EditorGUIUtility.standardVerticalSpacing;
Rect optionButton = GUILayoutUtility.GetLastRect();
optionButton.yMin = optionButton.yMax;
optionButton.yMax += DragonGUI.HeadIconsRect.height;
optionButton.xMin = optionButton.xMax - 64;
optionButton.center += Vector2.up * padding * 2f;
object data = pool.GetRaw(entityID);
Color fillColor = Color.clear;
Color backColor = Color.clear;
if (Event.current.type == EventType.Repaint)
{
switch (UserSettingsPrefs.instance.MetaBlockRectStyle)
{
default:
case MetaBlockRectStyle.Clean:
{
backColor = Color.white.SetAlpha(EscEditorConsts.MetaBlockCleanStyle_Alpha);
}
break;
case MetaBlockRectStyle.Edge:
{
backColor = Color.white.SetAlpha(EscEditorConsts.MetaBlockCleanStyle_Alpha);
fillColor = DragonGUI.SelectPanelColor(meta, index, total)
.SetAlpha(EscEditorConsts.MetaBlockEdgeStyle_Alpha);
}
break;
case MetaBlockRectStyle.Fill:
{
backColor = DragonGUI.SelectPanelColor(meta, index, total)
.Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE)
.SetAlpha(EscEditorConsts.MetaBlockFillStyle_Alpha);
}
break;
}
}
ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType);
using (DragonGUI.Layout.BeginVertical(UnityEditorUtility.GetWhiteStyle(), backColor))
{
using (DragonGUI.Layout.BeginVertical(UnityEditorUtility.GetWhiteEdge4Style(), fillColor))
{
//Close button
optionButton.xMin = optionButton.xMax - DragonGUI.HeadIconsRect.width;
if (DragonGUI.CloseButton(optionButton))
{
pool.Del(entityID);
return;
}
//Edit script button
if (cache.ScriptReference != null)
{
optionButton = DragonGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DragonGUI.ScriptAssetButton(optionButton, cache.ScriptReference);
}
//Description icon
if (string.IsNullOrEmpty(meta.Description.Text) == false)
{
optionButton = DragonGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DragonGUI.DescriptionIcon(optionButton, meta.Description.Text);
}
ref bool peakExpand = ref cache.ExpandStack.Peek();
var label = UnityEditorUtility.GetLabel(meta.Name);
if (peakExpand)
{
object data = pool.GetRaw(entityID);
if (DrawRuntimeData(ref cache.FieldInfoData, label, cache.ExpandStack, data, out object resultData, 0))
{
pool.SetRaw(entityID, resultData);
}
}
else
{
var foldoutStyle = EditorStyles.foldout;
Rect rect = GUILayoutUtility.GetRect(label, foldoutStyle);
peakExpand = EditorGUI.BeginFoldoutHeaderGroup(rect, false, label, foldoutStyle, null, null);
EditorGUILayout.EndFoldoutHeaderGroup();
}
}
}
}
}
private void DrawRuntimeClassComponent(int entityID, IEcsPool pool, int total, int index)
{
object data = pool.GetRaw(entityID);
Type componentType = data.GetType();
var meta = componentType.GetMeta();
if (meta.IsHidden == false || IsShowHidden)
{
ExpandStack expandStack = ExpandStack.Take(componentType);
float padding = EditorGUIUtility.standardVerticalSpacing;
Rect optionButton = GUILayoutUtility.GetLastRect();
@ -387,44 +528,67 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
optionButton.yMax += DragonGUI.HeadIconsRect.height;
optionButton.xMin = optionButton.xMax - 64;
optionButton.center += Vector2.up * padding * 2f;
//Canceling isExpanded
if (DragonGUI.ClickTest(optionButton))
Color fillColor = Color.clear;
Color backColor = Color.clear;
if (Event.current.type == EventType.Repaint)
{
ref bool isExpanded = ref expandMatrix.Down();
isExpanded = !isExpanded;
switch (UserSettingsPrefs.instance.MetaBlockRectStyle)
{
default:
case MetaBlockRectStyle.Clean:
{
backColor = Color.white.SetAlpha(EscEditorConsts.MetaBlockCleanStyle_Alpha);
}
break;
case MetaBlockRectStyle.Edge:
{
backColor = Color.white.SetAlpha(EscEditorConsts.MetaBlockCleanStyle_Alpha);
fillColor = DragonGUI.SelectPanelColor(meta, index, total)
.SetAlpha(EscEditorConsts.MetaBlockEdgeStyle_Alpha);
}
break;
case MetaBlockRectStyle.Fill:
{
backColor = DragonGUI.SelectPanelColor(meta, index, total)
.Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE)
.SetAlpha(EscEditorConsts.MetaBlockFillStyle_Alpha);
}
break;
}
}
Color panelColor = DragonGUI.SelectPanelColor(meta, index, total);
using (DragonGUI.Layout.BeginVertical(panelColor.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA)))
using (DragonGUI.Layout.BeginVertical(UnityEditorUtility.GetWhiteStyle(), backColor))
{
EditorGUI.BeginChangeCheck();
using (DragonGUI.Layout.BeginVertical(UnityEditorUtility.GetWhiteEdge4Style(), fillColor))
{
//Close button
optionButton.xMin = optionButton.xMax - DragonGUI.HeadIconsRect.width;
if (DragonGUI.CloseButton(optionButton))
{
pool.Del(entityID);
return;
}
//Edit script button
if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script))
{
optionButton = DragonGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DragonGUI.ScriptAssetButton(optionButton, script);
}
//Description icon
if (string.IsNullOrEmpty(meta.Description.Text) == false)
{
optionButton = DragonGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DragonGUI.DescriptionIcon(optionButton, meta.Description.Text);
}
//Close button
optionButton.xMin = optionButton.xMax - DragonGUI.HeadIconsRect.width;
if (DragonGUI.CloseButton(optionButton))
{
pool.Del(entityID);
return;
}
//Edit script button
if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script))
{
optionButton = DragonGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DragonGUI.ScriptAssetButton(optionButton, script);
}
//Description icon
if (string.IsNullOrEmpty(meta.Description.Text) == false)
{
optionButton = DragonGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DragonGUI.DescriptionIcon(optionButton, meta.Description.Text);
}
RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name);
RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name);
if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData, 0))
{
pool.SetRaw(entityID, resultData);
if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandStack, data, out object resultData, 0))
{
pool.SetRaw(entityID, resultData);
}
}
}
}
@ -434,13 +598,12 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
#region draw data
private bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData, int depth)
private bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandStack expandStack, object data, out object outData, int depth)
{
const int DEPTH_MAX = 24;
using (DragonGUI.CheckChanged())
{
outData = data;
object newData = data;
Type type = data == null ? typeof(void) : data.GetType();
@ -451,19 +614,19 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
return false;
}
RuntimeComponentReflectionCache cache = fieldInfoData.GetReflectionCache(type);
if (depth >= DEPTH_MAX || cache == null)
var reflectionCache = fieldInfoData.GetReflectionCache(type);
if (depth >= DEPTH_MAX || reflectionCache == null)
{
EditorGUILayout.TextField(label, "error");
return false;
}
ref bool isExpanded = ref expandMatrix.Down();
ref bool isExpanded = ref expandStack.Down();
bool childElementChanged = false;
var eventType = Event.current.type;
var label2 = "-";
var drawerType = cache.DrawerType;
var drawerType = reflectionCache.DrawerType;
if (isUnityObjectField)
{
@ -472,230 +635,260 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
switch (drawerType)
{
case DrawerType.UNDEFINED:
EditorGUILayout.LabelField(label, label2);
{
EditorGUILayout.LabelField(label, label2);
}
break;
case DrawerType.Ignored:
EditorGUILayout.LabelField(label, label2);
{
EditorGUILayout.LabelField(label, label2);
}
break;
case DrawerType.UnitySerializableComposite:
using (DragonGUI.CheckChanged())
{
RefEditorWrapper wrapper = cache.GetWrapper(_runtimeComponentsDepth);
wrapper.data = data;
wrapper.SO.Update();
wrapper.IsExpanded = isExpanded;
EditorGUILayout.PropertyField(wrapper.Property, label, true);
if (DragonGUI.Changed)
using (DragonGUI.CheckChanged())
{
wrapper.SO.ApplyModifiedProperties();
newData = wrapper.Data;
childElementChanged = true;
}
isExpanded = wrapper.IsExpanded;
}
RefEditorWrapper wrapper = reflectionCache.GetWrapper(_runtimeComponentsDepth);
wrapper.data = data;
wrapper.SO.Update();
wrapper.IsExpanded = isExpanded;
EditorGUILayout.PropertyField(wrapper.Property, label, true);
if (DragonGUI.Changed)
{
wrapper.SO.ApplyModifiedProperties();
newData = wrapper.Data;
childElementChanged = true;
}
isExpanded = wrapper.IsExpanded;
}
}
break;
case DrawerType.UnityNotSerializableComposite:
GUILayout.Space(DragonGUI.Spacing);
var foldoutStyle = EditorStyles.foldout;
Rect rect = GUILayoutUtility.GetRect(label, foldoutStyle);
//rect.xMin += EcsGUI.Indent;
isExpanded = EditorGUI.BeginFoldoutHeaderGroup(rect, isExpanded, label, foldoutStyle, null, null);
EditorGUILayout.EndFoldoutHeaderGroup();
if (isExpanded)
{
using (DragonGUI.UpIndentLevel())
GUILayout.Space(DragonGUI.Spacing);
var foldoutStyle = EditorStyles.foldout;
Rect rect = GUILayoutUtility.GetRect(label, foldoutStyle);
//rect.xMin += EcsGUI.Indent;
isExpanded = EditorGUI.BeginFoldoutHeaderGroup(rect, isExpanded, label, foldoutStyle, null, null);
EditorGUILayout.EndFoldoutHeaderGroup();
if (isExpanded)
{
for (int j = 0, jMax = cache.Fields.Length; j < jMax; j++)
using (DragonGUI.UpIndentLevel())
{
var field = cache.Fields[j];
if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData, depth + 1))
for (int j = 0, jMax = reflectionCache.Fields.Length; j < jMax; j++)
{
field.FieldInfo.SetValue(data, fieldData);
newData = data;
childElementChanged = true;
var field = reflectionCache.Fields[j];
if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandStack, field.FieldInfo.GetValue(data), out object fieldData, depth + 1))
{
field.FieldInfo.SetValue(data, fieldData);
newData = data;
childElementChanged = true;
}
}
}
}
}
break;
case DrawerType.UnityObject:
using (DragonGUI.CheckChanged())
{
var uobj = UnsafeUtility.As<object, UnityObject>(ref data);
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldInfoData.FieldType);
var newuobj = EditorGUILayout.ObjectField(label, uobj, fieldInfoData.FieldType, true);
if (uobj != newuobj)
using (DragonGUI.CheckChanged())
{
if (isComponent && newuobj is GameObject go)
var uobj = UnsafeUtility.As<object, UnityObject>(ref data);
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldInfoData.FieldType);
var newuobj = EditorGUILayout.ObjectField(label, uobj, fieldInfoData.FieldType, true);
if (uobj != newuobj)
{
newuobj = go.GetComponent(fieldInfoData.FieldType);
if (isComponent && newuobj is GameObject go)
{
newuobj = go.GetComponent(fieldInfoData.FieldType);
}
newData = newuobj;
childElementChanged = true;
}
newData = newuobj;
childElementChanged = true;
}
}
break;
case DrawerType.Enum:
if (eventType != EventType.Layout)
{
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumPopup(label, enumData);
if (eventType != EventType.Layout)
{
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumPopup(label, enumData);
}
else
{
EditorGUILayout.EnumPopup(label, default);
}
}
else
{
EditorGUILayout.EnumPopup(label, default);
}
break;
case DrawerType.EnumFlags:
if (eventType != EventType.Layout)
{
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumFlagsField(label, enumData);
if (eventType != EventType.Layout)
{
var enumData = UnsafeUtility.As<object, Enum>(ref data);
newData = EditorGUILayout.EnumFlagsField(label, enumData);
}
else
{
EditorGUILayout.EnumFlagsField(label, default);
}
}
else
{
EditorGUILayout.EnumFlagsField(label, default);
}
break;
case DrawerType.Bool:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.Toggle(label, (bool)data);
}
else
{
EditorGUILayout.Toggle(label, default);
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.Toggle(label, (bool)data);
}
else
{
EditorGUILayout.Toggle(label, default);
}
}
break;
case DrawerType.String:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.TextField(label, (string)data);
}
else
{
EditorGUILayout.TextField(label, default);
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.TextField(label, (string)data);
}
else
{
EditorGUILayout.TextField(label, default);
}
}
break;
case DrawerType.Float:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.FloatField(label, (float)data);
}
else
{
EditorGUILayout.FloatField(label, default);
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.FloatField(label, (float)data);
}
else
{
EditorGUILayout.FloatField(label, default);
}
}
break;
case DrawerType.Double:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.DoubleField(label, (double)data);
}
else
{
EditorGUILayout.DoubleField(label, default);
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.DoubleField(label, (double)data);
}
else
{
EditorGUILayout.DoubleField(label, default);
}
}
break;
case DrawerType.Byte:
if (eventType != EventType.Layout)
{
newData = (byte)EditorGUILayout.IntField(label, (byte)data);
}
else
{
EditorGUILayout.IntField(label, default);
if (eventType != EventType.Layout)
{
newData = (byte)EditorGUILayout.IntField(label, (byte)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
}
break;
case DrawerType.SByte:
if (eventType != EventType.Layout)
{
newData = (sbyte)EditorGUILayout.IntField(label, (sbyte)data);
}
else
{
EditorGUILayout.IntField(label, default);
if (eventType != EventType.Layout)
{
newData = (sbyte)EditorGUILayout.IntField(label, (sbyte)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
}
break;
case DrawerType.Short:
if (eventType != EventType.Layout)
{
newData = (short)EditorGUILayout.IntField(label, (short)data);
}
else
{
EditorGUILayout.IntField(label, default);
if (eventType != EventType.Layout)
{
newData = (short)EditorGUILayout.IntField(label, (short)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
}
break;
case DrawerType.UShort:
if (eventType != EventType.Layout)
{
newData = (ushort)EditorGUILayout.IntField(label, (ushort)data);
}
else
{
EditorGUILayout.IntField(label, default);
if (eventType != EventType.Layout)
{
newData = (ushort)EditorGUILayout.IntField(label, (ushort)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
}
break;
case DrawerType.Int:
if (eventType != EventType.Layout)
{
newData = (int)EditorGUILayout.IntField(label, (int)data);
}
else
{
EditorGUILayout.IntField(label, default);
if (eventType != EventType.Layout)
{
newData = (int)EditorGUILayout.IntField(label, (int)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
}
break;
case DrawerType.UInt:
if (eventType != EventType.Layout)
{
newData = (uint)EditorGUILayout.IntField(label, (int)(uint)data);
}
else
{
EditorGUILayout.IntField(label, default);
if (eventType != EventType.Layout)
{
newData = (uint)EditorGUILayout.IntField(label, (int)(uint)data);
}
else
{
EditorGUILayout.IntField(label, default);
}
}
break;
case DrawerType.Long:
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.LongField(label, (long)data);
}
else
{
EditorGUILayout.LongField(label, default);
if (eventType != EventType.Layout)
{
newData = EditorGUILayout.LongField(label, (long)data);
}
else
{
EditorGUILayout.LongField(label, default);
}
}
break;
case DrawerType.ULong:
if (eventType != EventType.Layout)
{
newData = (ulong)EditorGUILayout.LongField(label, (long)(ulong)data);
}
else
{
EditorGUILayout.LongField(label, default);
if (eventType != EventType.Layout)
{
newData = (ulong)EditorGUILayout.LongField(label, (long)(ulong)data);
}
else
{
EditorGUILayout.LongField(label, default);
}
}
break;
default:
EditorGUILayout.LabelField(label, label2);
{
EditorGUILayout.LabelField(label, label2);
}
break;
}
expandMatrix.Up();
expandStack.Up();
if (childElementChanged || DragonGUI.Changed)
{
outData = newData;
@ -705,7 +898,6 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
return false;
}
#endregion
public enum DrawerType
{
@ -731,6 +923,7 @@ namespace DCFApixels.DragonECS.Unity.Editors.X
Long,
ULong,
}
#endregion
}
}
#endif

View File

@ -120,7 +120,10 @@ namespace DCFApixels.DragonECS.Unity.Editors
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (AssemblyFilter.IsExcludedAssembly(assembly)) { continue; }
//var targetTypes = assembly.GetTypes().Where(type =>
// (type.IsGenericType || type.IsAbstract || type.IsInterface) == false &&
// type.IsSubclassOf(typeof(UnityObject)) == false &&
// type.GetCustomAttribute<SerializableAttribute>() != null);
foreach (var type in assembly.GetTypes())
{
@ -454,7 +457,11 @@ namespace DCFApixels.DragonECS.Unity.Editors
#region GetDefaultStyle
private static Texture2D _whiteTexture;
private static GUIStyle _whiteStyleWithPadding;
private static GUIStyle _whiteStyle;
private static GUIStyle _whiteEdgeStyle;
private static GUIStyle _transperentBlackBackgrounStyle;
private static GUIStyle _clearBackgrounStyle;
public static Texture2D GetWhiteTexture()
@ -467,16 +474,34 @@ namespace DCFApixels.DragonECS.Unity.Editors
}
private static bool IsNotInitializedStyle(GUIStyle style)
{
//return style == null || style.normal.background == null;
return style == null || style.normal.background == null;
}
public static GUIStyle GetWhiteStyleWithPadding()
{
if (IsNotInitializedStyle(_whiteStyleWithPadding))
{
_whiteStyleWithPadding = CreateStyle(GetWhiteTexture());
}
return _whiteStyleWithPadding;
}
public static GUIStyle GetWhiteStyle()
{
if (IsNotInitializedStyle(_whiteStyle))
{
_whiteStyle = CreateStyle(GetWhiteTexture(), GUI.skin.label);
_whiteStyle = CreateStyle(GetWhiteTexture());
_whiteStyle.padding = new RectOffset(0,0,0,0);
}
return _whiteStyle;
}
public static GUIStyle GetWhiteEdge4Style()
{
if (IsNotInitializedStyle(_whiteEdgeStyle))
{
_whiteEdgeStyle = CreateEdge4Style();
}
return _whiteEdgeStyle;
}
public static GUIStyle GetTransperentBlackBackgrounStyle()
{
if (IsNotInitializedStyle(_transperentBlackBackgrounStyle))
@ -502,7 +527,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
referenceStyle = GUI.skin.box;
}
GUIStyle result = new GUIStyle(GUI.skin.box);
GUIStyle result = new GUIStyle(referenceStyle);
Texture2D texture2D = texture;
result.hover.background = texture2D;
result.hover.scaledBackgrounds = Array.Empty<Texture2D>();
@ -514,6 +539,57 @@ namespace DCFApixels.DragonECS.Unity.Editors
result.normal.scaledBackgrounds = Array.Empty<Texture2D>();
return result;
}
private static GUIStyle CreateEdge4Style(GUIStyle referenceStyle = null)
{
const int Size = 8;
const int EdgeSize = 4;
var pixels = new Color[Size * Size];
for (var i = 0; i < pixels.Length; ++i)
{
pixels[i] = Color.clear;
}
for (int y = 0; y < Size; y++)
{
for (int x = 0; x < EdgeSize; x++)
{
pixels[y * Size + x] = Color.white;
}
}
var texture = new Texture2D(Size, Size)
{
filterMode = FilterMode.Point
};
texture.SetPixels(pixels);
texture.Apply();
if (referenceStyle == null)
{
referenceStyle = GUI.skin.box;
}
GUIStyle result = new GUIStyle(referenceStyle);
Texture2D texture2D = texture;
result.hover.background = texture2D;
result.hover.scaledBackgrounds = Array.Empty<Texture2D>();
result.focused.background = texture2D;
result.focused.scaledBackgrounds = Array.Empty<Texture2D>();
result.active.background = texture2D;
result.active.scaledBackgrounds = Array.Empty<Texture2D>();
result.normal.background = texture2D;
result.normal.scaledBackgrounds = Array.Empty<Texture2D>();
result.margin = new RectOffset(0, 0, 0, 0);
result.overflow = new RectOffset(0, 0, 0, 0);
result.border = new RectOffset(EdgeSize, 0, 0, 0);
result.contentOffset = Vector2.zero;
result.fixedHeight = 0;
result.fixedWidth = 0;
result.richText = false;
var l = GUI.skin.box.padding.left;
result.padding = new RectOffset(l + 4, l, l, l);
return result;
}
private static Texture2D CreateTexture(int width, int height, Color color)
{
var pixels = new Color[width * height];
@ -586,51 +662,5 @@ namespace DCFApixels.DragonECS.Unity.Editors
public void OnWorldResize(int newSize) { }
}
}
public static class AssemblyFilter
{
private static readonly HashSet<string> ExcludedPrefixes = new HashSet<string>
{
"Unity.",
"UnityEngine.",
"UnityEditor.",
"System.",
"mscorlib",
"netstandard",
"Mono.",
"Microsoft.",
"Mono.Security"
};
private static readonly HashSet<string> ExactedExcludedNames = new HashSet<string>
{
"System",
"System.Core",
"System.Xml",
"System.Runtime",
"System.Collections",
"System.Linq",
"System.Text.RegularExpressions",
"UnityEngine",
"UnityEditor",
};
public static bool IsExcludedAssembly(Assembly assembly)
{
string assemblyName = assembly.GetName().Name;
if (ExactedExcludedNames.Contains(assemblyName))
{
return true;
}
foreach (var prefix in ExcludedPrefixes)
{
if (assemblyName.StartsWith(prefix, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
}
}
#endif

View File

@ -2,7 +2,9 @@
{
internal static class EscEditorConsts
{
public const float COMPONENT_DRAWER_ALPHA = 0.26f;
public const float MetaBlockFillStyle_Alpha = 0.26f;
public const float MetaBlockEdgeStyle_Alpha = 0.74f;
public const float MetaBlockCleanStyle_Alpha = 0.05f;
public const float COMPONENT_DRAWER_DESATURATE = 0.86f;
public const int AUTO_COLOR_RAINBOW_MIN_RANGE = 7;
}

View File

@ -351,7 +351,7 @@ namespace DCFApixels.DragonECS.Unity.Editors
{
if (string.IsNullOrEmpty(item.scriptPath) == false)
{
_metaIDScriptPathPairs.Add(item.metaID, item.scriptPath);
_metaIDScriptPathPairs[item.metaID] = item.scriptPath;
}
}
}

View File

@ -28,6 +28,12 @@ namespace DCFApixels.DragonECS.Unity.Internal
r.xMin += with;
return (l, r);
}
public static Rect HorizontalGetLeft(in this Rect rect, float with)
{
Rect l = rect;
l.xMax = l.xMin + with;
return l;
}
public static (Rect, Rect) HorizontalSliceRight(in this Rect rect, float with)
{
Rect l = rect;

View File

@ -10,6 +10,19 @@ using System.Reflection;
using System.Runtime.InteropServices;
using UnityEngine;
namespace DCFApixels.DragonECS.Unity
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)]
public sealed class DragonMemberWrapperAttribute : Attribute
{
public string WrappedFieldName;
public DragonMemberWrapperAttribute(string wrappedFieldName)
{
WrappedFieldName = wrappedFieldName;
}
}
}
namespace DCFApixels.DragonECS
{
@ -178,10 +191,8 @@ namespace DCFApixels.DragonECS
{
case CloneMethod.Set:
return component;
#if DEBUG
case CloneMethod.Clone_Reflection:
return (T)component.Clone_Reflection();
#endif
case CloneMethod.ICloneable:
return (T)_defaultValueCloneable.Clone();
}

View File

@ -269,7 +269,7 @@ namespace DCFApixels.DragonECS.Unity.Docs.Editors
{
Color panelColor = DragonGUI.SelectPanelColor(meta.Color.ToMetaColor(), meta.IsCustomColor, index, total).Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE);
Color alphaPanelColor = panelColor;
alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA;
alphaPanelColor.a = EscEditorConsts.MetaBlockFillStyle_Alpha;
using (DragonGUI.Layout.BeginVertical(alphaPanelColor))
{

View File

@ -7,16 +7,6 @@ using UnityEngine;
namespace DCFApixels.DragonECS.Unity
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)]
public sealed class DragonMemberWrapperAttribute : Attribute
{
public string WrappedFieldName;
public DragonMemberWrapperAttribute(string wrappedFieldName)
{
WrappedFieldName = wrappedFieldName;
}
}
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public sealed class ReferenceDropDownAttribute : PropertyAttribute
{
public readonly Type[] AllowTypes;
@ -30,7 +20,6 @@ namespace DCFApixels.DragonECS.Unity
Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal));
}
}
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public sealed class ReferenceDropDownWithoutAttribute : Attribute
{
public readonly Type[] PredicateTypes;
@ -42,7 +31,6 @@ namespace DCFApixels.DragonECS.Unity
Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal));
}
}
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public sealed class DragonMetaBlockAttribute : PropertyAttribute { }
}