From 077f6b0e720cab341522af67f3774c7f81800000 Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Wed, 16 Apr 2025 09:36:51 +0800 Subject: [PATCH] update entlong & components display --- src/Connectors/EcsEntityConnect.cs | 4 + .../Editor/EcsEntityConnectEditor.cs | 9 +- src/DebugUtils/Editor/EntlongDrawer.cs | 59 ++- .../Monitors/Editor/EntityMonitorEditor.cs | 3 +- src/DebugUtils/Monitors/EntityMonitor.cs | 7 +- .../UnityDebugServiceStorage.cs | 12 +- src/Internal/Editor/DragonGUIContent.cs | 41 ++ src/Internal/Editor/DragonGUIContent.cs.meta | 2 + src/Internal/Editor/EcsGUI.Layout.cs | 415 ++-------------- src/Internal/Editor/EcsGUI.cs | 185 +++++-- src/Internal/Editor/ExtendedEditor.cs | 14 +- .../Editor/RuntimeComponentsDrawer.cs | 459 ++++++++++++++++++ .../Editor/RuntimeComponentsDrawer.cs.meta | 2 + src/Internal/Editor/SOWrappers/WrapperBase.cs | 15 +- src/Internal/Editor/UnityEditorUtility.cs | 20 +- src/Internal/Icons/FileIcon.png.meta | 37 +- src/Internal/Icons/HyperlinkIcon.png | Bin 0 -> 2021 bytes src/Internal/Icons/HyperlinkIcon.png.meta | 130 +++++ src/Internal/Icons/Icons.cs | 4 +- src/Internal/Icons/Icons.cs.meta | 1 + src/Internal/Icons/Resources/Icons.asset | 1 + 21 files changed, 978 insertions(+), 442 deletions(-) create mode 100644 src/Internal/Editor/DragonGUIContent.cs create mode 100644 src/Internal/Editor/DragonGUIContent.cs.meta create mode 100644 src/Internal/Editor/RuntimeComponentsDrawer.cs create mode 100644 src/Internal/Editor/RuntimeComponentsDrawer.cs.meta create mode 100644 src/Internal/Icons/HyperlinkIcon.png create mode 100644 src/Internal/Icons/HyperlinkIcon.png.meta diff --git a/src/Connectors/EcsEntityConnect.cs b/src/Connectors/EcsEntityConnect.cs index aceff68..cb9e103 100644 --- a/src/Connectors/EcsEntityConnect.cs +++ b/src/Connectors/EcsEntityConnect.cs @@ -9,6 +9,7 @@ using UnityEngine; using DCFApixels.DragonECS.Unity.Internal; #if UNITY_EDITOR using UnityEditor; +using DCFApixels.DragonECS.Unity.Editors; #endif namespace DCFApixels.DragonECS @@ -132,6 +133,9 @@ namespace DCFApixels.DragonECS _isConnectInvoked = true; _entity = entity; _world = world; +#if UNITY_EDITOR + world.Get().SetConnectLink(entity.GetIDUnchecked(), this); +#endif _connectedEntities.Add(GetInstanceID(), this); var goConnects = world.GetPool(); if (goConnects.Has(newEntityID)) diff --git a/src/Connectors/Editor/EcsEntityConnectEditor.cs b/src/Connectors/Editor/EcsEntityConnectEditor.cs index d80dc74..1416cb1 100644 --- a/src/Connectors/Editor/EcsEntityConnectEditor.cs +++ b/src/Connectors/Editor/EcsEntityConnectEditor.cs @@ -21,9 +21,10 @@ namespace DCFApixels.DragonECS.Unity.Editors private void DrawEntityInfo() { - bool isConnected = Target.Entity.TryUnpackForUnityEditor(out int id, out short gen, out short worldID, out EcsWorld world); - EcsGUI.EntityStatus status = IsMultipleTargets ? EcsGUI.EntityStatus.Undefined : isConnected ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive; - EcsGUI.Layout.EntityBarForAlive(status, id, gen, worldID); + //bool isConnected = Target.Entity.TryUnpackForUnityEditor(out int id, out short gen, out short worldID, out EcsWorld world); + //EcsGUI.EntityStatus status = IsMultipleTargets ? EcsGUI.EntityStatus.Undefined : isConnected ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive; + //EcsGUI.Layout.EntityField(status, id, gen, worldID); + EcsGUI.Layout.EntityField(Target.Entity); } private void DrawTemplates() @@ -104,7 +105,7 @@ namespace DCFApixels.DragonECS.Unity.Editors { if (world.IsNullOrDetroyed() == false) { - EcsGUI.Layout.DrawRuntimeComponents(entityID, world); + EcsGUI.Layout.DrawRuntimeComponents(entityID, world, true, true); } } } diff --git a/src/DebugUtils/Editor/EntlongDrawer.cs b/src/DebugUtils/Editor/EntlongDrawer.cs index 2049381..ebe5725 100644 --- a/src/DebugUtils/Editor/EntlongDrawer.cs +++ b/src/DebugUtils/Editor/EntlongDrawer.cs @@ -8,17 +8,62 @@ namespace DCFApixels.DragonECS.Unity.Editors [CustomPropertyDrawer(typeof(entlong))] internal class EntlongDrawer : ExtendedPropertyDrawer { + private float heightCache = 0; protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) { - using (EcsGUI.Disable) - { - EntitySlotInfo slotInfo = new EntitySlotInfo(property.FindPropertyRelative("_full").longValue); - var (labelRect, barRect) = position.HorizontalSliceLeft(EditorGUIUtility.labelWidth * 0.65f); + Rect labelRect, hyperlinkButtonRect; + (labelRect, position) = position.HorizontalSliceLeft(EditorGUIUtility.labelWidth * 0.65f); + (position, hyperlinkButtonRect) = position.HorizontalSliceRight(18f); - EditorGUI.LabelField(labelRect, label); - bool isAlive = EcsWorld.GetWorld(slotInfo.world).IsAlive(slotInfo.id, slotInfo.gen); - EcsGUI.EntityBar(barRect, false, isAlive ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive, slotInfo.id, slotInfo.gen, slotInfo.world); + bool drawFoldout = property.hasMultipleDifferentValues == false; + + bool isExpanded = false; + if (drawFoldout) + { + EditorGUI.BeginChangeCheck(); + isExpanded = EditorGUI.Foldout(labelRect, property.isExpanded, label); + if (EditorGUI.EndChangeCheck()) + { + property.isExpanded = isExpanded; + } } + else + { + EditorGUI.LabelField(labelRect, label); + } + + EntitySlotInfo entity = new EntitySlotInfo(property.FindPropertyRelative("_full").longValue); + EcsWorld.TryGetWorld(entity.world, out EcsWorld world); + + if (drawFoldout && isExpanded) + { + using (EcsGUI.UpIndentLevel()) + { + if (world != null && world.IsAlive(entity.id, entity.gen)) + { + EcsGUI.Layout.DrawRuntimeComponents(entity.id, world, false, false); + if (Event.current.type == EventType.Layout) + { + heightCache = GUILayoutUtility.GetLastRect().height; + } + } + } + } + EcsGUI.EntityField(position, property); + using (EcsGUI.SetEnable(world != null)) + { + EcsGUI.EntityHyperlinkButton(hyperlinkButtonRect, world, entity.id); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + const float UNITY_HEIGHT_CONSTANT = 18f; + if (property.hasMultipleDifferentValues) + { + return UNITY_HEIGHT_CONSTANT; + } + return Mathf.Max(heightCache, UNITY_HEIGHT_CONSTANT); } } } diff --git a/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs b/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs index d0c3c4b..f794872 100644 --- a/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs +++ b/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs @@ -19,7 +19,8 @@ namespace DCFApixels.DragonECS.Unity.Editors world.DelEntity(id); } } - EcsGUI.Layout.EntityBarForAlive(isAlive ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive, id, gen, worldID); + //EcsGUI.Layout.EntityBarForAlive(isAlive ? EcsGUI.EntityStatus.Alive : EcsGUI.EntityStatus.NotAlive, id, gen, worldID); + EcsGUI.Layout.EntityField(entity); var drawers = UnityEditorUtility._entityEditorBlockDrawers; if (drawers.Length > 0) diff --git a/src/DebugUtils/Monitors/EntityMonitor.cs b/src/DebugUtils/Monitors/EntityMonitor.cs index 2e1813c..3c17697 100644 --- a/src/DebugUtils/Monitors/EntityMonitor.cs +++ b/src/DebugUtils/Monitors/EntityMonitor.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using DCFApixels.DragonECS.Unity.Editors; +using UnityEngine; namespace DCFApixels.DragonECS.Unity.Internal { @@ -17,6 +18,10 @@ namespace DCFApixels.DragonECS.Unity.Internal public void Set(entlong entity) { _entity = entity; +#if UNITY_EDITOR + var world = entity.GetWorldUnchecked(); + world.Get().SetMonitorLink(entity.GetIDUnchecked(), this); +#endif } } } \ No newline at end of file diff --git a/src/DebugUtils/UnityDebugService/UnityDebugServiceStorage.cs b/src/DebugUtils/UnityDebugService/UnityDebugServiceStorage.cs index 6b4fef8..c558e0b 100644 --- a/src/DebugUtils/UnityDebugService/UnityDebugServiceStorage.cs +++ b/src/DebugUtils/UnityDebugService/UnityDebugServiceStorage.cs @@ -77,8 +77,8 @@ namespace DCFApixels.DragonECS.Unity.Internal { int indexof = INDEXED_LINK_PREV.Length - 1;// откатываю символ ∆ int stringIndexLength = e.LogString.IndexOf(INDEXED_LINK_POST) - indexof; - - if(stringIndexLength == path.Length) + + if (stringIndexLength == path.Length) { bool isSkip = false; for (int j = 1; j < stringIndexLength; j++) @@ -87,11 +87,11 @@ namespace DCFApixels.DragonECS.Unity.Internal var logchar = e.LogString[indexof + j]; if (pathchar != logchar) { isSkip = true; break; } } - + if (isSkip) { continue; } - + OpenIDE(e); - + break; } } @@ -149,7 +149,7 @@ namespace DCFApixels.DragonECS.Unity.Internal if (_consoleLogCounter > currentCount) { var l = _consoleLogCounter - currentCount; - if(l < inst._logEntries.Count) + if (l < inst._logEntries.Count) { inst._logEntries.FastRemoveSpan(0, l); } diff --git a/src/Internal/Editor/DragonGUIContent.cs b/src/Internal/Editor/DragonGUIContent.cs new file mode 100644 index 0000000..a902596 --- /dev/null +++ b/src/Internal/Editor/DragonGUIContent.cs @@ -0,0 +1,41 @@ +#if UNITY_EDITOR +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal struct DragonGUIContent + { + public static readonly DragonGUIContent Empty = new DragonGUIContent(); + public GUIContent value; + public DragonGUIContent(GUIContent value) { this.value = value; } + public DragonGUIContent(Texture texture) + { + value = UnityEditorUtility.GetLabelOrNull(texture); + } + public DragonGUIContent(Texture texture, string tooltip) + { + value = UnityEditorUtility.GetLabelOrNull(texture); + if (value != null) + { + value.tooltip = tooltip; + } + } + public DragonGUIContent(string text) + { + value = UnityEditorUtility.GetLabelOrNull(text); + } + public DragonGUIContent(string text, string tooltip) + { + value = UnityEditorUtility.GetLabelOrNull(text); + if (value != null) + { + value.tooltip = tooltip; + } + } + public static implicit operator DragonGUIContent(GUIContent a) { return new DragonGUIContent(a); } + public static implicit operator DragonGUIContent(Texture a) { return new DragonGUIContent(a); } + public static implicit operator DragonGUIContent(string a) { return new DragonGUIContent(a); } + public static implicit operator GUIContent(DragonGUIContent a) { return a.value; } + } +} +#endif \ No newline at end of file diff --git a/src/Internal/Editor/DragonGUIContent.cs.meta b/src/Internal/Editor/DragonGUIContent.cs.meta new file mode 100644 index 0000000..fe622bc --- /dev/null +++ b/src/Internal/Editor/DragonGUIContent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 83b46b5e659b87942857f69c1b056dcf \ No newline at end of file diff --git a/src/Internal/Editor/EcsGUI.Layout.cs b/src/Internal/Editor/EcsGUI.Layout.cs index c9c766d..66ed1b9 100644 --- a/src/Internal/Editor/EcsGUI.Layout.cs +++ b/src/Internal/Editor/EcsGUI.Layout.cs @@ -1,13 +1,10 @@ #if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Editors.X; using DCFApixels.DragonECS.Unity.Internal; -using System; using System.Collections.Generic; -using System.Reflection; -using Unity.Collections.LowLevel.Unsafe; using UnityEditor; using UnityEngine; using Color = UnityEngine.Color; -using UnityComponent = UnityEngine.Component; using UnityObject = UnityEngine.Object; namespace DCFApixels.DragonECS.Unity.Editors @@ -111,105 +108,51 @@ namespace DCFApixels.DragonECS.Unity.Editors } public static void DrawWorldComponents(EcsWorld world) { - bool isNull = world == null || world.IsDestroyed || world.ID == 0; - if (isNull) { return; } - using (BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) - { - IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout); - EditorGUILayout.EndFoldoutHeaderGroup(); - if (IsShowRuntimeComponents == false) { return; } - - var worldID = world.ID; - var cmps = world.GetWorldComponents(); - int index = -1; - int total = 9; - foreach (var cmp in cmps) - { - index++; - var meta = cmp.ComponentType.ToMeta(); - if (meta.IsHidden == false || IsShowHidden) - { - Type componentType = cmp.ComponentType; - - object data = cmp.GetRaw(worldID); - - ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType); - - float padding = EditorGUIUtility.standardVerticalSpacing; - Rect optionButton = GUILayoutUtility.GetLastRect(); - optionButton.yMin = optionButton.yMax; - optionButton.yMax += HeadIconsRect.height; - optionButton.xMin = optionButton.xMax - 64; - optionButton.center += Vector2.up * padding * 2f; - //Canceling isExpanded - if (ClickTest(optionButton)) - { - ref bool isExpanded = ref expandMatrix.Down(); - isExpanded = !isExpanded; - } - - Color panelColor = SelectPanelColor(meta, index, total); - using (BeginVertical(panelColor.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA))) - { - EditorGUI.BeginChangeCheck(); - - ////Close button - //optionButton.xMin = optionButton.xMax - HeadIconsRect.width; - //if (CloseButton(optionButton)) - //{ - // cmp.Del(worldID); - // return; - //} - - //Edit script button - if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script)) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - EcsGUI.ScriptAssetButton(optionButton, script); - } - //Description icon - if (string.IsNullOrEmpty(meta.Description.Text) == false) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - DescriptionIcon(optionButton, meta.Description.Text); - } - - RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name); - if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData)) - { - cmp.SetRaw(worldID, resultData); - } - - } - } - } - } + RuntimeComponentsDrawer.DrawWorldComponents(world); } #region entity bar - public static void EntityBarForAlive(EntityStatus status, int id, short gen, short world) + public static void EntityField(entlong entity) { - float width = EditorGUIUtility.currentViewWidth; - float height = EntityBarHeight; - EcsGUI.EntityBarForAlive(GUILayoutUtility.GetRect(width, height), status, id, gen, world); + EntityField(default(GUIContent), entity); } - public static void EntityBar(EntityStatus status, bool isPlaceholder, int id, short gen, short world) + public static void EntityField(string label, entlong entity) { - float width = EditorGUIUtility.currentViewWidth; - float height = EntityBarHeight; - EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height), isPlaceholder, status, id, gen, world); + EntityField(UnityEditorUtility.GetLabel(label), entity); } - public static void EntityBar(int id, short gen, short world) + public static unsafe void EntityField(GUIContent label, entlong entity) { float width = EditorGUIUtility.currentViewWidth; float height = EntityBarHeight; - EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height), id, gen, world); + EcsGUI.EntityField(GUILayoutUtility.GetRect(width, height), label, entity); } - public static void EntityBar() + public static void EntityField(EntitySlotInfo entity) + { + EntityField(default(GUIContent), entity); + } + public static void EntityField(string label, EntitySlotInfo entity) + { + EntityField(UnityEditorUtility.GetLabel(label), entity); + } + public static void EntityField(GUIContent label, EntitySlotInfo entity) { float width = EditorGUIUtility.currentViewWidth; float height = EntityBarHeight; - EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height)); + EcsGUI.EntityField(GUILayoutUtility.GetRect(width, height), label, entity); + } + public static void EntityField(SerializedProperty property) + { + EntityField(property, default(GUIContent)); + } + public static void EntityField(SerializedProperty property, string label) + { + EntityField(property, UnityEditorUtility.GetLabel(label)); + } + public static void EntityField(SerializedProperty property, GUIContent label) + { + float width = EditorGUIUtility.currentViewWidth; + float height = EntityBarHeight; + EcsGUI.EntityField(GUILayoutUtility.GetRect(width, height), property, label); } #endregion @@ -225,304 +168,18 @@ namespace DCFApixels.DragonECS.Unity.Editors { return EcsGUI.AddClearSystemButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 24f), out dropDownRect); } - public static void DrawRuntimeComponents(entlong entity, bool isWithFoldout = true) + public static void DrawRuntimeComponents(entlong entity, bool isWithFoldout, bool isRoot = true) { if (entity.TryUnpackForUnityEditor(out int entityID, out _, out _, out EcsWorld world)) { - DrawRuntimeComponents(entityID, world, isWithFoldout); + DrawRuntimeComponents(entityID, world, isWithFoldout, isRoot); } } - [ThreadStatic] - private static List _componentPoolsBuffer; - public static void DrawRuntimeComponents(int entityID, EcsWorld world, bool isWithFoldout = true) + public static void DrawRuntimeComponents(int entityID, EcsWorld world, bool isWithFoldout, bool isRoot) { - using (BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) - { - if (isWithFoldout) - { - IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout); - EditorGUILayout.EndFoldoutHeaderGroup(); - } - if (isWithFoldout == false || IsShowRuntimeComponents) - { - if (AddComponentButtons(out Rect dropDownRect)) - { - RuntimeComponentsUtility.GetAddComponentGenericMenu(world).Open(dropDownRect, entityID); - } - - using (SetBackgroundColor(GUI.color.SetAlpha(0.16f))) - { - GUILayout.Box("", UnityEditorUtility.GetWhiteStyle(), GUILayout.ExpandWidth(true)); - } - IsShowHidden = EditorGUI.Toggle(GUILayoutUtility.GetLastRect(), "Show Hidden", IsShowHidden); - - if (_componentPoolsBuffer == null) - { - _componentPoolsBuffer = new List(64); - } - world.GetComponentPoolsFor(entityID, _componentPoolsBuffer); - int i = 0; - //int iMax = _componentPoolsBuffer.Count; - foreach (var componentPool in _componentPoolsBuffer) - { - DrawRuntimeComponent(entityID, componentPool, 9, i++); - } - } - } + RuntimeComponentsDrawer.DrawRuntimeComponents(entityID, world, isWithFoldout, isRoot); } - private static void DrawRuntimeComponent(int entityID, IEcsPool pool, int total, int index) - { - var meta = pool.ComponentType.ToMeta(); - if (meta.IsHidden == false || IsShowHidden) - { - Type componentType = pool.ComponentType; - - object data = pool.GetRaw(entityID); - - ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType); - - float padding = EditorGUIUtility.standardVerticalSpacing; - Rect optionButton = GUILayoutUtility.GetLastRect(); - optionButton.yMin = optionButton.yMax; - optionButton.yMax += HeadIconsRect.height; - optionButton.xMin = optionButton.xMax - 64; - optionButton.center += Vector2.up * padding * 2f; - //Canceling isExpanded - if (ClickTest(optionButton)) - { - ref bool isExpanded = ref expandMatrix.Down(); - isExpanded = !isExpanded; - } - - Color panelColor = SelectPanelColor(meta, index, total); - - using (BeginVertical(panelColor.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA))) - { - EditorGUI.BeginChangeCheck(); - - //Close button - optionButton.xMin = optionButton.xMax - HeadIconsRect.width; - if (CloseButton(optionButton)) - { - pool.Del(entityID); - return; - } - //Edit script button - if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script)) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - EcsGUI.ScriptAssetButton(optionButton, script); - } - //Description icon - if (string.IsNullOrEmpty(meta.Description.Text) == false) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - DescriptionIcon(optionButton, meta.Description.Text); - } - - RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name); - - if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData)) - { - pool.SetRaw(entityID, resultData); - } - } - } - } - - #region Default DrawRuntimeData - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] - private static void ResetRuntimeComponentReflectionCache() - { - foreach (var item in _runtimeComponentReflectionCaches) - { - item.Value.Dispose(); - } - _runtimeComponentReflectionCaches.Clear(); - } - internal class RuntimeComponentReflectionCache : IDisposable - { - public readonly Type Type; - - public readonly bool IsUnityObjectType; - public readonly bool IsUnitySerializable; - public readonly bool IsUnmanaged; - - public readonly FieldInfoData[] Fields; - - public readonly RefEditorWrapper Wrapper; - - public RuntimeComponentReflectionCache(Type type) - { - Type = type; - - IsUnmanaged = UnsafeUtility.IsUnmanaged(type); - IsUnityObjectType = typeof(UnityObject).IsAssignableFrom(type); - IsUnitySerializable = IsUnityObjectType || (!type.IsGenericType && type.IsSerializable); - - Wrapper = RefEditorWrapper.Take(); - - if (type == typeof(void)) { return; } - - if (IsUnitySerializable == false) - { - var fs = type.GetFields(fieldFlags); - Fields = new FieldInfoData[fs.Length]; - for (int i = 0; i < fs.Length; i++) - { - var f = fs[i]; - Fields[i] = new FieldInfoData(f); - } - } - } - public void Dispose() - { - if(Wrapper != null) - { - UnityObject.DestroyImmediate(Wrapper); - } - } - - public readonly struct FieldInfoData - { - public readonly FieldInfo FieldInfo; - public readonly Type FieldType; - public readonly string UnityFormatName; - public readonly bool IsUnityObjectField; - public FieldInfoData(FieldInfo fieldInfo) - { - FieldInfo = fieldInfo; - FieldType = fieldInfo.FieldType; - IsUnityObjectField = typeof(UnityObject).IsAssignableFrom(fieldInfo.FieldType); - UnityFormatName = UnityEditorUtility.TransformFieldName(fieldInfo.Name); - } - public FieldInfoData(FieldInfo fieldInfo, Type fieldType, string unityFormatName) - { - FieldInfo = fieldInfo; - FieldType = fieldType; - UnityFormatName = unityFormatName; - IsUnityObjectField = typeof(UnityObject).IsAssignableFrom(fieldType); - } - } - } - private static Dictionary _runtimeComponentReflectionCaches = new Dictionary(); - private static RuntimeComponentReflectionCache GetRuntimeComponentReflectionCache(Type type) - { - if (_runtimeComponentReflectionCaches.TryGetValue(type, out RuntimeComponentReflectionCache result) == false) - { - result = new RuntimeComponentReflectionCache(type); - _runtimeComponentReflectionCaches.Add(type, result); - } - return result; - } - private static bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData) - { - outData = data; - Type type = data == null ? typeof(void) : data.GetType(); - - RuntimeComponentReflectionCache cache = GetRuntimeComponentReflectionCache(type); - - bool isUnityObjectField = fieldInfoData.IsUnityObjectField; - if (isUnityObjectField == false && data == null) - { - EditorGUILayout.TextField(label, "Null"); - return false; - } - bool isUnityObjectType = cache.IsUnityObjectType; - - ref bool isExpanded = ref expandMatrix.Down(); - bool changed = false; - - - if (cache.IsUnitySerializable == false) - { - isExpanded = EditorGUILayout.BeginFoldoutHeaderGroup(isExpanded, label, EditorStyles.foldout); - EditorGUILayout.EndFoldoutHeaderGroup(); - - if (isExpanded) - { - using (UpIndentLevel()) - { - for (int j = 0, jMax = cache.Fields.Length; j < jMax; j++) - { - var field = cache.Fields[j]; - if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData)) - { - field.FieldInfo.SetValue(data, fieldData); - outData = data; - changed = true; - } - } - } - } - } - else - { - Type fieldType = fieldInfoData.FieldType; - if (isUnityObjectType || isUnityObjectField) - { - EditorGUI.BeginChangeCheck(); - var uobj = UnsafeUtility.As(ref data); - - bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldType); - if (isComponent) - { - uobj = EditorGUILayout.ObjectField(label, uobj, typeof(UnityObject), true); - } - else - { - uobj = EditorGUILayout.ObjectField(label, uobj, fieldType, true); - } - - if (EditorGUI.EndChangeCheck()) - { - if (isComponent && uobj is GameObject go) - { - uobj = go.GetComponent(fieldType); - } - - outData = uobj; - changed = true; - } - } - else - { - EditorGUI.BeginChangeCheck(); - - RefEditorWrapper wrapper = cache.Wrapper; - - wrapper.data = data; - wrapper.SO.Update(); - - wrapper.IsExpanded = isExpanded; - try - { - EditorGUILayout.PropertyField(wrapper.Property, label, true); - } - catch (ArgumentException) - { - if (Event.current.type != EventType.Repaint) - { - throw; - } - } - - if (EditorGUI.EndChangeCheck()) - { - isExpanded = wrapper.IsExpanded; - wrapper.SO.ApplyModifiedProperties(); - outData = wrapper.Data; - changed = true; - } - //wrapper.Release(); - } - } - - expandMatrix.Up(); - return changed; - } - #endregion } } } diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs index 1900fb7..1688846 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR +using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Unity.Internal; using System; using System.Collections.Generic; @@ -282,7 +283,7 @@ namespace DCFApixels.DragonECS.Unity.Editors internal readonly static Color GreenColor = new Color32(75, 255, 0, 255); internal readonly static Color RedColor = new Color32(255, 0, 75, 255); - private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); + internal static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); public static float EntityBarHeight => EditorGUIUtility.singleLineHeight + 3f; @@ -327,12 +328,11 @@ namespace DCFApixels.DragonECS.Unity.Editors Add = 1, Clear = 2, } - [Flags] public enum EntityStatus : byte { NotAlive = 0, - Alive = 1 << 0, - Undefined = 1 << 1, + Alive = 1, + Undefined = 2, } #endregion @@ -366,7 +366,37 @@ namespace DCFApixels.DragonECS.Unity.Editors #endregion #region small elems - public static void DrawIcon(Rect position, Texture icon, float iconPadding, string description) + public static void DrawTextureSoftColor(Rect position, Texture texture) + { + if (Event.current.type == EventType.Repaint) + { + Graphics.DrawTexture(position, texture, new Rect(0f, 0f, 1f, 1f), 0, 0, 0, 0, GUI.color * 0.5f, null); + } + } + public static void DrawTexture(Rect position, Texture texture) + { + if (Event.current.type == EventType.Repaint) + { + Graphics.DrawTexture(position, texture, new Rect(0f, 0f, 1f, 1f), 0, 0, 0, 0, GUI.color, null); + } + } + public static void DrawRectSoftColor(Rect position, Color color) + { + if (Event.current.type == EventType.Repaint) + { + Texture texture = UnityEditorUtility.GetWhiteTexture(); + Graphics.DrawTexture(position, texture, new Rect(0f, 0f, 1f, 1f), 0, 0, 0, 0, GUI.color * color * 0.5f, null); + } + } + public static void DrawRect(Rect position, Color color) + { + if (Event.current.type == EventType.Repaint) + { + Texture texture = UnityEditorUtility.GetWhiteTexture(); + Graphics.DrawTexture(position, texture, new Rect(0f, 0f, 1f, 1f), 0, 0, 0, 0, GUI.color * color, null); + } + } + public static void DrawIcon(Rect position, Texture icon, float iconPadding, string tooltip) { if (position.width != position.height) { @@ -378,8 +408,8 @@ namespace DCFApixels.DragonECS.Unity.Editors } using (SetColor(GUI.enabled ? GUI.color : GUI.color * new Color(1f, 1f, 1f, 0.4f))) { - GUI.Label(position, UnityEditorUtility.GetLabel(string.Empty, description)); - GUI.DrawTexture(RectUtility.AddPadding(position, iconPadding), icon); + GUI.Label(position, UnityEditorUtility.GetLabel(string.Empty, tooltip)); + DrawTextureSoftColor(RectUtility.AddPadding(position, iconPadding), icon); } } public static (bool, bool) IconButtonGeneric(Rect position) @@ -413,7 +443,25 @@ namespace DCFApixels.DragonECS.Unity.Editors } } + public static void EntityHyperlinkButton(Rect position, EcsWorld world, int entityID) + { + var current = Event.current; + var hover = IconHoverScan(position, current); + var click = IconButton(position, Icons.Instance.HyperlinkIcon, 2f, string.Empty); + if (GUI.enabled) + { + if (click) + { + var obj = world.Get().GetLink(entityID); + if (obj != null) + { + EditorGUIUtility.PingObject(obj); + Selection.activeObject = obj; + } + } + } + } public static void ScriptAssetButton(Rect position, MonoScript script) { var current = Event.current; @@ -489,20 +537,99 @@ namespace DCFApixels.DragonECS.Unity.Editors #endregion #region entity bar - public static void EntityBarForAlive(Rect position, EntityStatus status, int id, short gen, short world) + internal readonly struct EntityLinksComponent : IEcsWorldComponent { - EntityBar(position, status != EntityStatus.Alive, status, id, gen, world); + private readonly Storage _storage; + private EntityLinksComponent(Storage storage) { _storage = storage; } + public void SetConnectLink(int entityID, EcsEntityConnect link) { _storage.links[entityID].connect = link; } + public void SetMonitorLink(int entityID, EntityMonitor link) { _storage.links[entityID].monitor = link; } + public EcsEntityConnect GetConnectLink(int entityID) { return _storage.links[entityID].connect; } + public EntityMonitor GetMonitorLink(int entityID) { return _storage.links[entityID].monitor; } + public UnityEngine.Object GetLink(int entityID) + { + ref var links = ref _storage.links[entityID]; + if (links.connect != null) + { + return links.connect; + } + return links.monitor; + } + void IEcsWorldComponent.Init(ref EntityLinksComponent component, EcsWorld world) + { + component = new EntityLinksComponent(new Storage(world)); + } + void IEcsWorldComponent.OnDestroy(ref EntityLinksComponent component, EcsWorld world) + { + component = default; + } + private class Storage : IEcsWorldEventListener + { + private readonly EcsWorld _world; + public (EcsEntityConnect connect, EntityMonitor monitor)[] links; + public Storage(EcsWorld world) + { + _world = world; + _world.AddListener(this); + links = new (EcsEntityConnect, EntityMonitor)[_world.Capacity]; + } + public void OnWorldResize(int newSize) { Array.Resize(ref links, newSize); } + public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { } + public void OnWorldDestroy() { } + } } - public static void EntityBar(Rect position, int id, short gen, short world) + public static void EntityField(Rect position, entlong entity) { - EntityBar_Internal(position, false, id, gen, world); + EntityField(position, DragonGUIContent.Empty, entity); } - public static void EntityBar(Rect position) + public static unsafe void EntityField(Rect position, DragonGUIContent label, entlong entity) { - EntityBar_Internal(position, true); + EntityField(position, label, (EntitySlotInfo)entity); } - public static void EntityBar(Rect position, bool isPlaceholder, EntityStatus status, int id = 0, short gen = 0, short world = 0) + public static void EntityField(Rect position, EntitySlotInfo entity) { + EntityField(position, DragonGUIContent.Empty, entity); + } + public static void EntityField(Rect position, DragonGUIContent label, EntitySlotInfo entity) + { + bool isAlive = false; + if (EcsWorld.TryGetWorld(entity.world, out EcsWorld world)) + { + isAlive = world.IsAlive(entity.id, entity.gen); + } + EntityField_Internal(position, label, entity.id == 0, isAlive ? EntityStatus.Alive : EntityStatus.NotAlive, entity.id, entity.gen, entity.world); + } + public static void EntityField(Rect position, SerializedProperty property) + { + EntityField(position, property, DragonGUIContent.Empty); + } + public static void EntityField(Rect position, SerializedProperty property, DragonGUIContent label) + { + EntitySlotInfo entity = new EntitySlotInfo(property.FindPropertyRelative("_full").longValue); + + if (property.hasMultipleDifferentValues) + { + EntityField_Internal(position, label, true, EntityStatus.Undefined, 0, 0, 0); + } + else + { + bool isAlive = false; + if (EcsWorld.TryGetWorld(entity.world, out EcsWorld world)) + { + isAlive = world.IsAlive(entity.id, entity.gen); + } + EntityField_Internal(position, label, entity.id == 0, isAlive ? EntityStatus.Alive : EntityStatus.NotAlive, entity.id, entity.gen, entity.world); + } + } + + internal static void EntityField_Internal(Rect position, GUIContent label, bool isPlaceholder, EntityStatus status, int id, short gen, short world) + { + if (label != null) + { + Rect labelRect; + (labelRect, position) = position.HorizontalSliceLeft(EditorGUIUtility.labelWidth * 0.65f); + EditorGUI.LabelField(labelRect, label); + } + using (SetLabelWidth(0f)) { var (entityInfoRect, statusRect) = RectUtility.VerticalSliceBottom(position, 3f); @@ -511,10 +638,10 @@ namespace DCFApixels.DragonECS.Unity.Editors switch (status) { case EntityStatus.NotAlive: - statusColor = EcsGUI.RedColor; + statusColor = RedColor; break; case EntityStatus.Alive: - statusColor = EcsGUI.GreenColor; + statusColor = GreenColor; break; default: statusColor = new Color32(200, 200, 200, 255); @@ -524,18 +651,18 @@ namespace DCFApixels.DragonECS.Unity.Editors statusColor.a = 0.6f; EditorGUI.DrawRect(statusRect, statusColor); - EntityBar_Internal(entityInfoRect, isPlaceholder, id, gen, world); + EntityFieldContent_Internal(entityInfoRect, isPlaceholder, id, gen, world); } } - private static void EntityBar_Internal(Rect position, bool isPlaceHolder, int id = 0, short gen = 0, short world = 0) + private static void EntityFieldContent_Internal(Rect position, bool isPlaceHolder, int id, short gen, short world) { - using (SetLabelWidth(0f)) + using (SetLabelWidth(0f)) using (SetIndentLevel(0)) { Color w = Color.gray; w.a = 0.6f; Color b = Color.black; b.a = 0.55f; - EditorGUI.DrawRect(position, w); + DrawRectSoftColor(position, w); var (idRect, genWorldRect) = RectUtility.HorizontalSliceLerp(position, 0.4f); var (genRect, worldRect) = RectUtility.HorizontalSliceLerp(genWorldRect, 0.5f); @@ -543,22 +670,19 @@ namespace DCFApixels.DragonECS.Unity.Editors idRect = RectUtility.AddPadding(idRect, 2, 1, 0, 0); genRect = RectUtility.AddPadding(genRect, 1, 1, 0, 0); worldRect = RectUtility.AddPadding(worldRect, 1, 2, 0, 0); - EditorGUI.DrawRect(idRect, b); - EditorGUI.DrawRect(genRect, b); - EditorGUI.DrawRect(worldRect, b); + DrawRectSoftColor(idRect, b); + DrawRectSoftColor(genRect, b); + DrawRectSoftColor(worldRect, b); GUIStyle style = UnityEditorUtility.GetInputFieldCenterAnhor(); if (isPlaceHolder) { - using (new EditorGUI.DisabledScope(true)) + using (SetAlpha(0.85f)) using (Disable) { GUI.Label(idRect, "Entity ID", style); - using (SetAlpha(0.85f)) - { - GUI.Label(genRect, "Generation", style); - GUI.Label(worldRect, "World ID", style); - } + GUI.Label(genRect, "Generation", style); + GUI.Label(worldRect, "World ID", style); } } else @@ -1031,7 +1155,8 @@ namespace DCFApixels.DragonECS.Unity.Editors var x = Group.Splited.GetEnumerator(); x.MoveNext(); return x.Current.GetHashCode() ^ state; - }; + } + ; } } #endregion diff --git a/src/Internal/Editor/ExtendedEditor.cs b/src/Internal/Editor/ExtendedEditor.cs index f9d4e6c..6880c6d 100644 --- a/src/Internal/Editor/ExtendedEditor.cs +++ b/src/Internal/Editor/ExtendedEditor.cs @@ -44,7 +44,12 @@ namespace DCFApixels.DragonECS.Unity.Editors get { return UserSettingsPrefs.instance.IsShowHidden; } set { UserSettingsPrefs.instance.IsShowHidden = value; } } - private static ComponentColorMode ComponentColorMode + protected bool IsShowRuntimeComponents + { + get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; } + set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; } + } + protected static ComponentColorMode ComponentColorMode { get { return UserSettingsPrefs.instance.ComponentColorMode; } set { UserSettingsPrefs.instance.ComponentColorMode = value; } @@ -190,7 +195,12 @@ namespace DCFApixels.DragonECS.Unity.Editors get { return UserSettingsPrefs.instance.IsShowHidden; } set { UserSettingsPrefs.instance.IsShowHidden = value; } } - private static ComponentColorMode ComponentColorMode + protected bool IsShowRuntimeComponents + { + get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; } + set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; } + } + protected static ComponentColorMode ComponentColorMode { get { return UserSettingsPrefs.instance.ComponentColorMode; } set { UserSettingsPrefs.instance.ComponentColorMode = value; } diff --git a/src/Internal/Editor/RuntimeComponentsDrawer.cs b/src/Internal/Editor/RuntimeComponentsDrawer.cs new file mode 100644 index 0000000..8cd41b7 --- /dev/null +++ b/src/Internal/Editor/RuntimeComponentsDrawer.cs @@ -0,0 +1,459 @@ +#if UNITY_EDITOR +using DCFApixels.DragonECS.Unity.Internal; +using System; +using System.Collections.Generic; +using System.Reflection; +using Unity.Collections.LowLevel.Unsafe; +using UnityEditor; +using UnityEngine; +using Color = UnityEngine.Color; +using UnityComponent = UnityEngine.Component; +using UnityObject = UnityEngine.Object; + + +namespace DCFApixels.DragonECS.Unity.Editors.X +{ + internal class RuntimeComponentsDrawer + { + private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void ResetRuntimeComponentReflectionCache() + { + RefEditorWrapper.ResetStaticState(); + foreach (var item in _runtimeComponentReflectionCaches) + { + item.Value.ResetWrappers(); + } + //_runtimeComponentReflectionCaches.Clear(); + } + private const int RuntimeComponentsMaxDepth = 2; + private static RuntimeComponentsDrawer[] _drawers; + private static int _runtimeComponentsDepth = 2; + static RuntimeComponentsDrawer() + { + _drawers = new RuntimeComponentsDrawer[RuntimeComponentsMaxDepth + 1]; + _drawers[0] = new RuntimeComponentsDrawer(); + _drawers[1] = new RuntimeComponentsDrawer(); + _drawers[2] = new RuntimeComponentsDrawer(); + } + + private List _componentPoolsBuffer = new List(64); + + + #region Properties + private static ComponentColorMode AutoColorMode + { + get { return UserSettingsPrefs.instance.ComponentColorMode; } + set { UserSettingsPrefs.instance.ComponentColorMode = value; } + } + private static bool IsShowHidden + { + get { return UserSettingsPrefs.instance.IsShowHidden; } + set { UserSettingsPrefs.instance.IsShowHidden = value; } + } + private static bool IsShowRuntimeComponents + { + get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; } + set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; } + } + #endregion + + #region reflection cache + internal class RuntimeComponentReflectionCache + { + public readonly Type Type; + + public readonly bool IsUnityObjectType; + public readonly bool IsUnitySerializable; + public readonly bool IsUnmanaged; + + public readonly FieldInfoData[] Fields; + + private RefEditorWrapper[] _wrappers = new RefEditorWrapper[2]; + public RefEditorWrapper GetWrapper(int depth) + { + return _wrappers[depth]; + } + + public RuntimeComponentReflectionCache(Type type) + { + + Type = type; + ResetWrappers(); + IsUnmanaged = UnsafeUtility.IsUnmanaged(type); + IsUnityObjectType = typeof(UnityObject).IsAssignableFrom(type); + IsUnitySerializable = IsUnityObjectType || (!type.IsGenericType && type.IsSerializable); + + if (type == typeof(void)) { return; } + + if (IsUnitySerializable == false) + { + var fieldInfos = type.GetFields(fieldFlags); + Fields = new FieldInfoData[fieldInfos.Length]; + for (int i = 0; i < fieldInfos.Length; i++) + { + var fieldInfo = fieldInfos[i]; + Fields[i] = new FieldInfoData(fieldInfo); + } + } + } + public void ResetWrappers() + { + _wrappers[0] = RefEditorWrapper.Take(); + _wrappers[1] = RefEditorWrapper.Take(); + } + public readonly struct FieldInfoData + { + public readonly FieldInfo FieldInfo; + public readonly Type FieldType; + public readonly string UnityFormatName; + public readonly bool IsUnityObjectField; + public readonly bool IsPassToSerialize; + public readonly RuntimeComponentReflectionCache ValueTypeReflectionCache; + public FieldInfoData(FieldInfo fieldInfo) + { + FieldInfo = fieldInfo; + FieldType = fieldInfo.FieldType; + IsUnityObjectField = typeof(UnityObject).IsAssignableFrom(fieldInfo.FieldType); + UnityFormatName = UnityEditorUtility.TransformFieldName(fieldInfo.Name); + IsPassToSerialize = + (fieldInfo.IsPublic || fieldInfo.HasAttribute() || fieldInfo.HasAttribute()) && + (fieldInfo.IsInitOnly || fieldInfo.HasAttribute()) == false; + ValueTypeReflectionCache = FieldType.IsValueType ? GetRuntimeComponentReflectionCache(FieldType) : null; + } + public FieldInfoData(FieldInfo fieldInfo, Type fieldType, string unityFormatName, bool isPassToSerialize = true) + { + FieldInfo = fieldInfo; + FieldType = fieldType; + UnityFormatName = unityFormatName; + IsUnityObjectField = typeof(UnityObject).IsAssignableFrom(fieldType); + IsPassToSerialize = isPassToSerialize; + ValueTypeReflectionCache = FieldType.IsValueType ? GetRuntimeComponentReflectionCache(FieldType) : null; + } + public RuntimeComponentReflectionCache GetReflectionCache(Type type) + { + if (ValueTypeReflectionCache != null) + { + return ValueTypeReflectionCache; + } + return GetRuntimeComponentReflectionCache(type); + } + } + } + private static Dictionary _runtimeComponentReflectionCaches = new Dictionary(); + private static RuntimeComponentReflectionCache GetRuntimeComponentReflectionCache(Type type) + { + if (_runtimeComponentReflectionCaches.TryGetValue(type, out RuntimeComponentReflectionCache result) == false) + { + result = new RuntimeComponentReflectionCache(type); + _runtimeComponentReflectionCaches.Add(type, result); + } + return result; + } + #endregion + + #region draw world component + public static void DrawWorldComponents(EcsWorld world) + { + if (_runtimeComponentsDepth == 0) + { + _drawers[_runtimeComponentsDepth].DrawWorldComponents_Internal(world); + } + } + private void DrawWorldComponents_Internal(EcsWorld world) + { + bool isNull = world == null || world.IsDestroyed || world.ID == 0; + if (isNull) { return; } + using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) + { + IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout); + EditorGUILayout.EndFoldoutHeaderGroup(); + if (IsShowRuntimeComponents == false) { return; } + + var worldID = world.ID; + var cmps = world.GetWorldComponents(); + int index = -1; + int total = 9; + foreach (var cmp in cmps) + { + index++; + var meta = cmp.ComponentType.ToMeta(); + if (meta.IsHidden == false || IsShowHidden) + { + Type componentType = cmp.ComponentType; + + object data = cmp.GetRaw(worldID); + + ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType); + + float padding = EditorGUIUtility.standardVerticalSpacing; + Rect optionButton = GUILayoutUtility.GetLastRect(); + optionButton.yMin = optionButton.yMax; + optionButton.yMax += EcsGUI.HeadIconsRect.height; + optionButton.xMin = optionButton.xMax - 64; + optionButton.center += Vector2.up * padding * 2f; + //Canceling isExpanded + if (EcsGUI.ClickTest(optionButton)) + { + ref bool isExpanded = ref expandMatrix.Down(); + isExpanded = !isExpanded; + } + + Color panelColor = EcsGUI.SelectPanelColor(meta, index, total); + using (EcsGUI.Layout.BeginVertical(panelColor.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA))) + { + EditorGUI.BeginChangeCheck(); + + //Edit script button + if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script)) + { + optionButton = EcsGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + EcsGUI.ScriptAssetButton(optionButton, script); + } + //Description icon + if (string.IsNullOrEmpty(meta.Description.Text) == false) + { + optionButton = EcsGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + EcsGUI.DescriptionIcon(optionButton, meta.Description.Text); + } + + RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name); + if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData)) + { + cmp.SetRaw(worldID, resultData); + } + + } + } + } + } + } + #endregion + + #region draw entity component + public static void DrawRuntimeComponents(int entityID, EcsWorld world, bool isWithFoldout, bool isRoot) + { + if (isRoot) + { + _runtimeComponentsDepth = 0; + } + else + { + _runtimeComponentsDepth++; + } + + _drawers[_runtimeComponentsDepth].DrawRuntimeComponents(entityID, world, isWithFoldout); + + _runtimeComponentsDepth--; + } + private void DrawRuntimeComponents(int entityID, EcsWorld world, bool isWithFoldout) + { + using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetTransperentBlackBackgrounStyle())) using (EcsGUI.SetIndentLevel(0)) + { + if (_runtimeComponentsDepth >= RuntimeComponentsMaxDepth) + { + GUILayout.Label("Max depth for inspecting components at runtime"); + return; + } + if (isWithFoldout) + { + IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout); + EditorGUILayout.EndFoldoutHeaderGroup(); + } + if (isWithFoldout == false || IsShowRuntimeComponents) + { + if (EcsGUI.Layout.AddComponentButtons(out Rect dropDownRect)) + { + RuntimeComponentsUtility.GetAddComponentGenericMenu(world).Open(dropDownRect, entityID); + } + + using (EcsGUI.SetBackgroundColor(GUI.color.SetAlpha(0.16f))) + { + GUILayout.Box("", UnityEditorUtility.GetWhiteStyle(), GUILayout.ExpandWidth(true)); + } + 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); + } + } + } + } + private void DrawRuntimeComponent(int entityID, IEcsPool pool, int total, int index) + { + var meta = pool.ComponentType.ToMeta(); + if (meta.IsHidden == false || IsShowHidden) + { + Type componentType = pool.ComponentType; + + object data = pool.GetRaw(entityID); + + ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType); + + float padding = EditorGUIUtility.standardVerticalSpacing; + Rect optionButton = GUILayoutUtility.GetLastRect(); + optionButton.yMin = optionButton.yMax; + optionButton.yMax += EcsGUI.HeadIconsRect.height; + optionButton.xMin = optionButton.xMax - 64; + optionButton.center += Vector2.up * padding * 2f; + //Canceling isExpanded + if (EcsGUI.ClickTest(optionButton)) + { + ref bool isExpanded = ref expandMatrix.Down(); + isExpanded = !isExpanded; + } + + Color panelColor = EcsGUI.SelectPanelColor(meta, index, total); + + using (EcsGUI.Layout.BeginVertical(panelColor.SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA))) + { + EditorGUI.BeginChangeCheck(); + + //Close button + optionButton.xMin = optionButton.xMax - EcsGUI.HeadIconsRect.width; + if (EcsGUI.CloseButton(optionButton)) + { + pool.Del(entityID); + return; + } + //Edit script button + if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script)) + { + optionButton = EcsGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + EcsGUI.ScriptAssetButton(optionButton, script); + } + //Description icon + if (string.IsNullOrEmpty(meta.Description.Text) == false) + { + optionButton = EcsGUI.HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + EcsGUI.DescriptionIcon(optionButton, meta.Description.Text); + } + + RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name); + + if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData)) + { + pool.SetRaw(entityID, resultData); + } + } + } + } + #endregion + + + + #region draw data + private bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData) + { + outData = data; + Type type = data == null ? typeof(void) : data.GetType(); + + RuntimeComponentReflectionCache cache = fieldInfoData.GetReflectionCache(type); + + bool isUnityObjectField = fieldInfoData.IsUnityObjectField; + if (isUnityObjectField == false && data == null) + { + EditorGUILayout.TextField(label, "Null"); + return false; + } + bool isUnityObjectType = cache.IsUnityObjectType; + + ref bool isExpanded = ref expandMatrix.Down(); + bool changed = false; + + + if (cache.IsUnitySerializable == false) + { + isExpanded = EditorGUILayout.BeginFoldoutHeaderGroup(isExpanded, label, EditorStyles.foldout); + EditorGUILayout.EndFoldoutHeaderGroup(); + + if (isExpanded) + { + using (EcsGUI.UpIndentLevel()) + { + for (int j = 0, jMax = cache.Fields.Length; j < jMax; j++) + { + var field = cache.Fields[j]; + if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData)) + { + field.FieldInfo.SetValue(data, fieldData); + outData = data; + changed = true; + } + } + } + } + } + else + { + Type fieldType = fieldInfoData.FieldType; + if (isUnityObjectType || isUnityObjectField) + { + EditorGUI.BeginChangeCheck(); + var uobj = UnsafeUtility.As(ref data); + + bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldType); + if (isComponent) + { + uobj = EditorGUILayout.ObjectField(label, uobj, typeof(UnityObject), true); + } + else + { + uobj = EditorGUILayout.ObjectField(label, uobj, fieldType, true); + } + + if (EditorGUI.EndChangeCheck()) + { + if (isComponent && uobj is GameObject go) + { + uobj = go.GetComponent(fieldType); + } + + outData = uobj; + changed = true; + } + } + else + { + EditorGUI.BeginChangeCheck(); + + RefEditorWrapper wrapper = cache.GetWrapper(_runtimeComponentsDepth); + + wrapper.data = data; + wrapper.SO.Update(); + + wrapper.IsExpanded = isExpanded; + try + { + EditorGUILayout.PropertyField(wrapper.Property, label, true); + } + catch (ArgumentException) + { + if (Event.current.type != EventType.Repaint) + { + throw; + } + } + finally + { + if (EditorGUI.EndChangeCheck()) + { + wrapper.SO.ApplyModifiedProperties(); + outData = wrapper.Data; + changed = true; + } + isExpanded = wrapper.IsExpanded; + } + } + } + + expandMatrix.Up(); + return changed; + } + #endregion + } +} +#endif \ No newline at end of file diff --git a/src/Internal/Editor/RuntimeComponentsDrawer.cs.meta b/src/Internal/Editor/RuntimeComponentsDrawer.cs.meta new file mode 100644 index 0000000..5827921 --- /dev/null +++ b/src/Internal/Editor/RuntimeComponentsDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 69581c5eb282d024baca88cb374bf5af \ No newline at end of file diff --git a/src/Internal/Editor/SOWrappers/WrapperBase.cs b/src/Internal/Editor/SOWrappers/WrapperBase.cs index ac551dd..2d0649b 100644 --- a/src/Internal/Editor/SOWrappers/WrapperBase.cs +++ b/src/Internal/Editor/SOWrappers/WrapperBase.cs @@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS.Unity.Editors public abstract void Release(); } [Serializable] - internal abstract class WrapperBase : WrapperBase + internal abstract class WrapperBase : WrapperBase, IDisposable where TSelf : WrapperBase { @@ -28,6 +28,14 @@ namespace DCFApixels.DragonECS.Unity.Editors private bool _isReleased = false; private static Stack _wrappers = new Stack(); + public static void ResetStaticState() + { + foreach (var item in _wrappers) + { + UnityEngine.Object.DestroyImmediate(item); + } + _wrappers.Clear(); + } public sealed override bool IsExpanded { @@ -88,6 +96,11 @@ namespace DCFApixels.DragonECS.Unity.Editors { Release((TSelf)this); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + Release(); + } } } #endif diff --git a/src/Internal/Editor/UnityEditorUtility.cs b/src/Internal/Editor/UnityEditorUtility.cs index b1738ef..6828100 100644 --- a/src/Internal/Editor/UnityEditorUtility.cs +++ b/src/Internal/Editor/UnityEditorUtility.cs @@ -312,8 +312,8 @@ namespace DCFApixels.DragonECS.Unity.Editors break; case SerializedPropertyType.Gradient: #if UNITY_2022_1_OR_NEWER - property.gradientValue = new Gradient();; - + property.gradientValue = new Gradient(); ; + #else Debug.LogWarning($"Unsupported SerializedPropertyType: {property.propertyType}"); #endif @@ -402,6 +402,22 @@ namespace DCFApixels.DragonECS.Unity.Editors _singletonContent.image = null; return _singletonContent; } + public static GUIContent GetLabelOrNull(string name, string tooltip = null) + { + if (string.IsNullOrEmpty(name)) + { + return null; + } + return GetLabel(name, tooltip); + } + public static GUIContent GetLabelOrNull(Texture value, string tooltip = null) + { + if (value == null) + { + return null; + } + return GetLabel(value, tooltip); + } public static GUIContent GetLabel(string name, string tooltip = null) { if (_singletonContent == null) diff --git a/src/Internal/Icons/FileIcon.png.meta b/src/Internal/Icons/FileIcon.png.meta index 45d706e..fdfdfef 100644 --- a/src/Internal/Icons/FileIcon.png.meta +++ b/src/Internal/Icons/FileIcon.png.meta @@ -3,11 +3,11 @@ guid: 4f1ca6aa9d407844485856184c785946 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 1 + sRGBTexture: 0 linearTexture: 0 fadeOut: 0 borderMipMap: 0 @@ -20,11 +20,12 @@ TextureImporter: externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 + flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 - ignoreMasterTextureLimit: 0 + ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -63,8 +64,10 @@ TextureImporter: textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 1 platformSettings: - - serializedVersion: 3 + - serializedVersion: 4 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 @@ -74,9 +77,10 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 + - serializedVersion: 4 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 @@ -86,9 +90,10 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 + - serializedVersion: 4 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 @@ -98,12 +103,27 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] + customData: physicsShape: [] bones: [] spriteID: @@ -113,10 +133,11 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] + spriteCustomMetadata: + entries: [] nameFileIdTable: {} - spritePackingTag: + mipmapLimitGroupName: pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/src/Internal/Icons/HyperlinkIcon.png b/src/Internal/Icons/HyperlinkIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..4741cc046b35ab09203d977fe09647f9fac1fdf2 GIT binary patch literal 2021 zcmcIle{j=e7!I(q4J;dj8wjFV0A1PAq)qxGkpkN~ScQ%;3Jf`AY4WAbt!+w@uI=Ct zHyMf!^?*AN(PJl|c!viAy;C?C8^=Tu5apCRktqmzq6qQ_a(MI0)>h5~+&}g%&6ni) zp7(j5_syHNHPv&BBPNVM5X9)Ia@WE$svkMS;lJ9{bQ7L(qg6{)1Q|I-KZYP%wvI;- z!*R)1r`37qvAi5MbAs##=0rFO(FihqW+KY*4M0QvARt9t*tG+PF;o&<*by+nxT!TDW9NYM1qSF7Bi{mlm>de4~B-r8MLZZHo_<=z4s(meaR>wYJn=p z6dqJIf`~Rb9ZcXed!sQW)Ss!q6Ceb_5T-(5mQ1KoF*$i zSq`NuRg-2xt+d&J7B7(^f*e;(x}wwu;N~>o!eG^GI7#Cc+GlaFl!c|NC9r%XIRN#- zMi4lS8yr{`Br!P{sMpJSBC5tkc;IonFeu6_Ndn7pB57ru4qS9N{W#;KDctY0Gq9fo zJKz~VBl>Oqy5N4d%*S;5^!)>UE66<8nfQ$~n`5C9*0d0ajHjyTACoND=q=mHGM1c`$3x*0jE6Pfk zgMA`}xd0%dkpPDNqozU*$%%H#6 zc)iF#z*4uRd$>0^oddM-Ab_L~DEo&L|}BJL+%eQ<^UAEl>k z<%3)#0N~^#Fg+PUA29<(A^u&j{%3cMqcj}OIDMI!uJ9r=pFsptD{%V$g!@qh8Per( zm-*_t&u*Gq>|QXwXU>_UuXOl2wr*_QF{kKl8gz@L+qc)5K>P4yc+d4uJ}s|$X^n9~ zsWx{@LCM6`dp4U2ZxkQx`|9=E?D>@^-=qSU#p}zyr7pw|Emu!nJTT+4j#baDU+a0I zY~QA#hkLW>lpE}c z&RzcR+oZys2V3k5>euxp%%(%aw#52YpFuPhUi)CB!P?wZ(JIf{@g=q~_o#8~aznD? zncgY+i|3ta>>eA;KHGcz@tr-NmtC5&=a-s9w$D`ERdSt}zo;|syVYG6wk=xmux0Tq z^J683qDjpo+HZ}^DL%Q@m0xt~$KFZqSXN8RtaZnJ-Td15wrS1zrbF*0T{Hi3LPtHzVzXQ8@12HK8l^oue;K`_aWP^G1Hoh^A6Ib z`I~l6zMWsR?6<6|6MNfEoNF&AM!p{Y#;B)GgqOXQH~UE8H+G~!%ii}Fxb$bw&wT~A YhS@x=eY-*hSM(3Dr?T4petCV%-=7k%(f|Me literal 0 HcmV?d00001 diff --git a/src/Internal/Icons/HyperlinkIcon.png.meta b/src/Internal/Icons/HyperlinkIcon.png.meta new file mode 100644 index 0000000..4cab159 --- /dev/null +++ b/src/Internal/Icons/HyperlinkIcon.png.meta @@ -0,0 +1,130 @@ +fileFormatVersion: 2 +guid: 2a89f8c59dad13641b9c51337e8fd7ad +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Icons/Icons.cs b/src/Internal/Icons/Icons.cs index 2e989d5..c43c39e 100644 --- a/src/Internal/Icons/Icons.cs +++ b/src/Internal/Icons/Icons.cs @@ -43,7 +43,8 @@ namespace DCFApixels.DragonECS.Unity.Internal private Texture _labelIconType = null; [SerializeField] private Texture _labelIconMeta = null; - + [SerializeField] + private Texture _hyperlinkIcon = null; private Texture2D _dummy; private Texture2D _dummyRed; @@ -117,6 +118,7 @@ namespace DCFApixels.DragonECS.Unity.Internal internal Texture VisibilityIconOff { get { return _visibilityIconOff != null ? _visibilityIconOff : Dummy; } } internal Texture LabelIconType { get { return _labelIconType != null ? _labelIconType : Dummy; } } internal Texture LabelIconMeta { get { return _labelIconMeta != null ? _labelIconMeta : Dummy; } } + internal Texture HyperlinkIcon { get { return _hyperlinkIcon != null ? _hyperlinkIcon : Dummy; } } #endif } } \ No newline at end of file diff --git a/src/Internal/Icons/Icons.cs.meta b/src/Internal/Icons/Icons.cs.meta index c0e2920..409ef6c 100644 --- a/src/Internal/Icons/Icons.cs.meta +++ b/src/Internal/Icons/Icons.cs.meta @@ -21,6 +21,7 @@ MonoImporter: - _visibilityIconOff: {fileID: 2800000, guid: 1f25a5ca611092642a8ee4e08fafcd43, type: 3} - _labelIconType: {fileID: 2800000, guid: 5476d6e1435981e4cbc915a080f93ee6, type: 3} - _labelIconMeta: {fileID: 2800000, guid: ebb82b09315bde749a10dfa45e64067c, type: 3} + - _hyperlinkIcon: {fileID: 2800000, guid: 2a89f8c59dad13641b9c51337e8fd7ad, type: 3} executionOrder: 0 icon: {instanceID: 0} userData: diff --git a/src/Internal/Icons/Resources/Icons.asset b/src/Internal/Icons/Resources/Icons.asset index 71ecd06..e8a620d 100644 --- a/src/Internal/Icons/Resources/Icons.asset +++ b/src/Internal/Icons/Resources/Icons.asset @@ -29,3 +29,4 @@ MonoBehaviour: _visibilityIconOff: {fileID: 2800000, guid: 1f25a5ca611092642a8ee4e08fafcd43, type: 3} _labelIconType: {fileID: 2800000, guid: 5476d6e1435981e4cbc915a080f93ee6, type: 3} _labelIconMeta: {fileID: 2800000, guid: ebb82b09315bde749a10dfa45e64067c, type: 3} + _hyperlinkIcon: {fileID: 2800000, guid: 2a89f8c59dad13641b9c51337e8fd7ad, type: 3}