DragonECS-Unity/src/Internal/Editor/UnityEditorUtility.cs

592 lines
22 KiB
C#
Raw Normal View History

2025-03-20 10:34:20 +08:00
using System;
2024-03-07 21:22:48 +08:00
using System.Collections.Generic;
2024-09-12 01:35:37 +08:00
using System.Linq;
2024-03-07 03:18:00 +08:00
using System.Text;
using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Editors
{
2024-04-29 22:12:51 +08:00
internal static partial class UnityEditorUtility
2024-03-07 03:18:00 +08:00
{
#region TransformFieldName
2024-03-10 04:56:29 +08:00
public static string TransformToUpperName(string name)
{
if (name.Length <= 0)
{
return name;
}
StringBuilder b = new StringBuilder();
bool nextWorld = true;
bool prewIsUpper = false;
for (int i = 0; i < name.Length; i++)
{
char c = name[i];
if (char.IsLetter(c) == false)
{
nextWorld = true;
prewIsUpper = false;
continue;
}
bool isUpper = char.IsUpper(c);
if (isUpper)
{
if (nextWorld == false && prewIsUpper == false)
{
b.Append('_');
}
}
b.Append(char.ToUpper(c));
nextWorld = false;
prewIsUpper = isUpper;
}
return b.ToString();
}
2024-03-07 03:18:00 +08:00
public static string TransformFieldName(string name)
{
if (name.Length <= 0)
{
return name;
}
StringBuilder b = new StringBuilder();
bool nextWorld = true;
bool prewIsUpper = false;
for (int i = 0; i < name.Length; i++)
{
char c = name[i];
if (char.IsLetter(c) == false)
{
nextWorld = true;
prewIsUpper = false;
continue;
}
bool isUpper = char.IsUpper(c);
if (isUpper)
{
if (nextWorld == false && prewIsUpper == false)
{
b.Append(' ');
nextWorld = true;
}
}
if (nextWorld)
{
b.Append(char.ToUpper(c));
}
else
{
b.Append(c);
}
nextWorld = false;
prewIsUpper = isUpper;
}
return b.ToString();
}
#endregion
2024-04-29 22:12:51 +08:00
}
}
#if UNITY_EDITOR
namespace DCFApixels.DragonECS.Unity.Editors
{
2025-03-20 10:34:20 +08:00
using DCFApixels.DragonECS.Unity.Internal;
2024-09-29 15:59:14 +08:00
using UnityEditor;
2024-12-08 15:38:04 +08:00
using Assembly = System.Reflection.Assembly;
2024-09-29 15:59:14 +08:00
2024-04-29 22:12:51 +08:00
[InitializeOnLoad]
internal static partial class UnityEditorUtility
{
static UnityEditorUtility()
{
2025-03-20 10:34:20 +08:00
const int PREWARMUP_LIST_SIZE = 64;
OnLoad();
2024-12-08 15:38:04 +08:00
_integrationAssembly = typeof(UnityEditorUtility).Assembly;
2025-03-20 10:34:20 +08:00
List<Type> serializableTypes = new List<Type>(PREWARMUP_LIST_SIZE);
List<TypeMeta> typeWithMetaIDMetas = new List<TypeMeta>(PREWARMUP_LIST_SIZE);
List<TypeMeta> serializableTypeWithMetaIDMetas = new List<TypeMeta>(PREWARMUP_LIST_SIZE);
List<EntityEditorBlockDrawer> entityEditorBlockDrawers = new List<EntityEditorBlockDrawer>(PREWARMUP_LIST_SIZE);
2024-09-16 19:31:01 +08:00
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
2024-10-01 19:05:51 +08:00
//var targetTypes = assembly.GetTypes().Where(type =>
// (type.IsGenericType || type.IsAbstract || type.IsInterface) == false &&
// type.IsSubclassOf(typeof(UnityObject)) == false &&
// type.GetCustomAttribute<SerializableAttribute>() != null);
2025-03-10 13:08:18 +08:00
foreach (var type in assembly.GetTypes())
{
2025-03-20 10:34:20 +08:00
bool hasMetaID = false;
if (TypeMeta.TryGetCustomMeta(type, out TypeMeta meta) && meta.IsHasMetaID())
2025-03-10 13:08:18 +08:00
{
2025-03-20 10:34:20 +08:00
typeWithMetaIDMetas.Add(meta);
hasMetaID = true;
2025-03-10 13:08:18 +08:00
}
2024-09-16 19:31:01 +08:00
2025-03-20 10:34:20 +08:00
if (type.IsConcreteType())
{
if (typeof(EntityEditorBlockDrawer).IsAssignableFrom(type))
{
var drawer = (EntityEditorBlockDrawer)Activator.CreateInstance(type);
entityEditorBlockDrawers.Add(drawer);
}
if (type.IsUnityObject() == false && type.GetConstructor(Type.EmptyTypes) != null)
{
serializableTypes.Add(type);
if (hasMetaID)
{
serializableTypeWithMetaIDMetas.Add(meta);
}
}
}
}
2024-09-16 19:31:01 +08:00
}
2024-09-29 15:59:14 +08:00
_serializableTypes = serializableTypes.ToArray();
2025-03-20 10:34:20 +08:00
_typeWithMetaIDMetas = typeWithMetaIDMetas.ToArray();
_serializableTypeWithMetaIDMetas = serializableTypeWithMetaIDMetas.ToArray();
2025-03-10 13:08:18 +08:00
_entityEditorBlockDrawers = entityEditorBlockDrawers.ToArray();
2024-10-01 09:09:40 +08:00
2025-03-20 10:34:20 +08:00
_metaIDCollisions = MetaID.FindMetaIDCollisions(_typeWithMetaIDMetas);
IsHasAnyMetaIDCollision = _metaIDCollisions.IsHasAnyCollision;
if (_metaIDCollisions.IsHasAnyCollision)
{
StringBuilder log = new StringBuilder();
log.Append("MetaID identifier collisions detected. Some functions that use MetaID were disabled until the collisions were fixed. List of collisions:\r\n");
{
int i = 0;
foreach (var collision in _metaIDCollisions)
{
i++;
log.Append('├');
log.Append($"ID: {collision.MetaID}\r\n");
int j = 0;
foreach (var meta in collision)
{
j++;
log.Append('│');
if (j == collision.Count)
{
log.Append('└');
}
else
{
log.Append('├');
}
log.Append($"Type: {meta.TypeName}\r\n");
}
}
}
Debug.LogError(log.ToString());
}
foreach (var item in _typeWithMetaIDMetas)
2024-10-01 09:09:40 +08:00
{
_metaIDTypePairs[item.MetaID] = item.Type;
}
2024-09-16 19:31:01 +08:00
//Array.Sort(_serializableTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal));
//_noHiddenSerializableTypes = _serializableTypes.Where(o => {
// var atr = o.GetCustomAttribute<MetaTagsAttribute>();
// return atr != null && atr.Tags.Contains(MetaTags.HIDDEN);
//}).ToArray();
2024-04-29 22:12:51 +08:00
}
2024-09-29 15:59:14 +08:00
2025-03-21 19:59:23 +08:00
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void OnLoad()
{
EcsWorld.ResetStaticState();
if (DebugService.IsNullOrDefault)
{
UnityDebugService.Activate();
}
2025-03-21 19:59:23 +08:00
}
2024-12-08 15:38:04 +08:00
internal static readonly Assembly _integrationAssembly;
2024-09-16 19:31:01 +08:00
internal static readonly Type[] _serializableTypes;
2025-03-20 10:34:20 +08:00
internal static readonly TypeMeta[] _typeWithMetaIDMetas;
2024-09-29 15:59:14 +08:00
internal static readonly TypeMeta[] _serializableTypeWithMetaIDMetas;
2025-03-20 10:34:20 +08:00
internal static readonly EntityEditorBlockDrawer[] _entityEditorBlockDrawers;
internal static readonly MetaID.CollisionList _metaIDCollisions;
public static readonly bool IsHasAnyMetaIDCollision;
2024-09-29 23:31:12 +08:00
private static readonly Dictionary<string, Type> _metaIDTypePairs = new Dictionary<string, Type>();
public static bool TryGetTypeForMetaID(string metaID, out Type type)
{
return _metaIDTypePairs.TryGetValue(metaID, out type);
}
2024-09-16 19:31:01 +08:00
//private static Type[] _noHiddenSerializableTypes;
2024-05-04 01:43:39 +08:00
private static GUIContent _singletonIconContent = null;
2024-04-29 22:12:51 +08:00
private static GUIContent _singletonContent = null;
2025-05-14 20:19:40 +08:00
private static GUIContent _singleton2Content = null;
2024-05-13 19:20:07 +08:00
private static GUIStyle _inputFieldCenterAnhor = null;
2025-03-10 22:59:48 +08:00
private static Dictionary<Type, MonoScript> _scriptsAssets = new Dictionary<Type, MonoScript>(256);
2024-06-15 16:53:28 +08:00
internal static void ResetValues(this SerializedProperty property, bool isExpand = false)
2024-09-15 00:00:32 +08:00
{
ResetValues_Internal(property.Copy(), isExpand, property.depth);
}
private static void ResetValues_Internal(SerializedProperty property, bool isExpand, int depth)
{
property.isExpanded = isExpand;
switch (property.propertyType)
{
case SerializedPropertyType.Generic:
try
//TODO хз как с этим работать, но это говно постоянно кидает
//InvalidOperationException: The operation is not possible when moved past all properties (Next returned false)
//и не дает инструментов и шансов этого избежать
{
2024-09-15 00:00:32 +08:00
bool x = true;
while (property.Next(x) && property.depth > depth)
{
2024-09-15 00:00:32 +08:00
ResetValues_Internal(property, isExpand, property.depth);
x = false;
}
}
catch (Exception) { }
break;
case SerializedPropertyType.Integer:
property.intValue = default;
break;
case SerializedPropertyType.Boolean:
property.boolValue = default;
break;
case SerializedPropertyType.Float:
property.floatValue = default;
break;
case SerializedPropertyType.String:
property.stringValue = string.Empty;
break;
case SerializedPropertyType.Color:
property.colorValue = default;
break;
case SerializedPropertyType.ObjectReference:
2024-09-16 19:31:01 +08:00
property.objectReferenceValue = default;
break;
case SerializedPropertyType.LayerMask:
property.intValue = default;
break;
case SerializedPropertyType.Enum:
property.enumValueIndex = default;
break;
case SerializedPropertyType.Vector2:
property.vector2Value = default;
break;
case SerializedPropertyType.Vector3:
property.vector3Value = default;
break;
case SerializedPropertyType.Vector4:
property.vector4Value = default;
break;
case SerializedPropertyType.Rect:
property.rectValue = default;
break;
case SerializedPropertyType.ArraySize:
property.ClearArray();
break;
case SerializedPropertyType.Character:
property.intValue = default;
break;
case SerializedPropertyType.AnimationCurve:
property.animationCurveValue = new AnimationCurve();
break;
case SerializedPropertyType.Bounds:
property.boundsValue = default;
break;
case SerializedPropertyType.Gradient:
#if UNITY_2022_1_OR_NEWER
2025-04-16 09:36:51 +08:00
property.gradientValue = new Gradient(); ;
#else
Debug.LogWarning($"Unsupported SerializedPropertyType: {property.propertyType}");
#endif
break;
case SerializedPropertyType.Quaternion:
property.quaternionValue = Quaternion.identity;
break;
case SerializedPropertyType.ExposedReference:
2024-09-16 19:31:01 +08:00
property.objectReferenceValue = default;
break;
case SerializedPropertyType.FixedBufferSize:
for (int i = 0, iMax = property.fixedBufferSize; i < iMax; i++)
{
property.GetFixedBufferElementAtIndex(i).intValue = default;
}
break;
case SerializedPropertyType.Vector2Int:
property.vector2IntValue = default;
break;
case SerializedPropertyType.Vector3Int:
property.vector3IntValue = default;
break;
case SerializedPropertyType.RectInt:
property.rectIntValue = default;
break;
case SerializedPropertyType.BoundsInt:
property.boundsIntValue = default;
break;
case SerializedPropertyType.ManagedReference:
property.managedReferenceValue = default;
break;
case SerializedPropertyType.Hash128:
property.hash128Value = default;
break;
default:
Debug.LogWarning($"Unsupported SerializedPropertyType: {property.propertyType}");
break;
}
}
2024-06-15 16:53:28 +08:00
internal static bool TryGetScriptAsset(Type type, out MonoScript script)
{
2025-03-10 22:59:48 +08:00
if (_scriptsAssets.TryGetValue(type, out script) == false)
2024-06-15 16:53:28 +08:00
{
script = null;
2024-06-15 19:45:31 +08:00
string name = type.Name;
int indexOf = name.LastIndexOf('`');
2024-09-10 19:13:31 +08:00
if (indexOf >= 0)
2024-06-15 19:45:31 +08:00
{
name = name.Substring(0, indexOf);
}
var guids = AssetDatabase.FindAssets($"{name} t:MonoScript");
2024-06-15 16:53:28 +08:00
for (var i = 0; i < guids.Length; i++)
{
MonoScript textAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(AssetDatabase.GUIDToAssetPath(guids[i]));
2024-06-15 19:45:31 +08:00
if (textAsset != null && textAsset.name == name)
2024-06-15 16:53:28 +08:00
{
script = textAsset;
break;
}
}
2025-03-10 22:59:48 +08:00
_scriptsAssets.Add(type, script);
2024-06-15 16:53:28 +08:00
}
return script != null;
}
2024-03-07 03:18:00 +08:00
#region Label
2024-05-13 19:20:07 +08:00
public static GUIStyle GetInputFieldCenterAnhor()
{
if (_inputFieldCenterAnhor == null)
{
GUIStyle style = new GUIStyle(EditorStyles.numberField);
style.alignment = TextAnchor.MiddleCenter;
style.font = EditorStyles.boldFont;
_inputFieldCenterAnhor = style;
}
return _inputFieldCenterAnhor;
}
2024-03-10 08:10:58 +08:00
public static GUIContent GetLabelTemp()
{
if (_singletonContent == null)
{
_singletonContent = new GUIContent();
}
2024-10-01 18:04:53 +08:00
_singletonContent.text = string.Empty;
_singletonContent.tooltip = string.Empty;
_singletonContent.image = null;
2024-03-10 08:10:58 +08:00
return _singletonContent;
}
2025-04-16 09:36:51 +08:00
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);
}
2024-03-07 03:18:00 +08:00
public static GUIContent GetLabel(string name, string tooltip = null)
{
if (_singletonContent == null)
{
_singletonContent = new GUIContent();
}
_singletonContent.text = name;
2024-03-09 09:42:04 +08:00
_singletonContent.image = null;
_singletonContent.tooltip = tooltip;
return _singletonContent;
}
public static GUIContent GetLabel(Texture image, string tooltip = null)
{
2024-05-04 01:43:39 +08:00
if (_singletonIconContent == null)
2024-03-09 09:42:04 +08:00
{
2024-05-04 01:43:39 +08:00
_singletonIconContent = new GUIContent();
2024-03-09 09:42:04 +08:00
}
2024-05-04 01:43:39 +08:00
_singletonIconContent.text = string.Empty;
_singletonIconContent.image = image;
_singletonIconContent.tooltip = tooltip;
return _singletonIconContent;
2024-03-07 03:18:00 +08:00
}
2025-05-14 20:19:40 +08:00
public static GUIContent GetLabel2(string name, string tooltip = null)
{
if (_singleton2Content == null)
{
_singleton2Content = new GUIContent();
}
_singleton2Content.text = name;
_singleton2Content.image = null;
_singleton2Content.tooltip = tooltip;
return _singleton2Content;
}
2024-03-07 03:18:00 +08:00
#endregion
2025-03-10 19:41:17 +08:00
#region GetDefaultStyle
2025-03-10 17:56:18 +08:00
private static Texture2D _whiteTexture;
private static GUIStyle _whiteStyle;
private static GUIStyle _transperentBlackBackgrounStyle;
2025-03-10 19:41:17 +08:00
private static GUIStyle _clearBackgrounStyle;
2025-03-10 17:56:18 +08:00
public static Texture2D GetWhiteTexture()
{
if (_whiteTexture == null)
{
_whiteTexture = CreateTexture(2, 2, Color.white);
}
return _whiteTexture;
}
2025-03-10 19:41:17 +08:00
private static bool IsNotInitializedStyle(GUIStyle style)
{
return style == null || style.normal.background == null;
}
2025-03-10 17:56:18 +08:00
public static GUIStyle GetWhiteStyle()
{
2025-03-10 19:41:17 +08:00
if (IsNotInitializedStyle(_whiteStyle))
2025-03-10 17:56:18 +08:00
{
_whiteStyle = CreateStyle(GetWhiteTexture(), GUI.skin.label);
}
return _whiteStyle;
}
public static GUIStyle GetTransperentBlackBackgrounStyle()
{
2025-03-10 19:41:17 +08:00
if (IsNotInitializedStyle(_transperentBlackBackgrounStyle))
2025-03-10 17:56:18 +08:00
{
_transperentBlackBackgrounStyle = CreateStyle(CreateTexture(2, 2, new Color(0, 0, 0, 0.2f)), GUI.skin.label);
}
return _transperentBlackBackgrounStyle;
}
2025-03-10 19:41:17 +08:00
public static GUIStyle GetClearBackgrounStyle()
{
if (IsNotInitializedStyle(_clearBackgrounStyle))
{
_clearBackgrounStyle = CreateStyle(CreateTexture(2, 2, new Color(0, 0, 0, 0)), GUI.skin.label);
}
return _clearBackgrounStyle;
}
2025-03-10 17:56:18 +08:00
#endregion
2024-03-07 03:18:00 +08:00
#region GetStyle
2025-03-10 17:56:18 +08:00
private static GUIStyle CreateStyle(Texture2D texture, GUIStyle referenceStyle = null)
2024-03-07 03:18:00 +08:00
{
2025-03-10 17:56:18 +08:00
if (referenceStyle == null)
{
referenceStyle = GUI.skin.box;
}
2024-03-07 03:18:00 +08:00
GUIStyle result = new GUIStyle(GUI.skin.box);
2025-03-10 17:56:18 +08:00
Texture2D texture2D = texture;
2024-03-07 03:18:00 +08:00
result.hover.background = texture2D;
2024-05-02 21:02:16 +08:00
result.hover.scaledBackgrounds = Array.Empty<Texture2D>();
2024-03-07 03:18:00 +08:00
result.focused.background = texture2D;
2024-05-02 21:02:16 +08:00
result.focused.scaledBackgrounds = Array.Empty<Texture2D>();
2024-03-07 03:18:00 +08:00
result.active.background = texture2D;
2024-05-02 21:02:16 +08:00
result.active.scaledBackgrounds = Array.Empty<Texture2D>();
2024-03-07 03:18:00 +08:00
result.normal.background = texture2D;
2024-05-02 21:02:16 +08:00
result.normal.scaledBackgrounds = Array.Empty<Texture2D>();
2024-03-07 03:18:00 +08:00
return result;
}
private static Texture2D CreateTexture(int width, int height, Color color)
{
var pixels = new Color[width * height];
for (var i = 0; i < pixels.Length; ++i)
2025-03-10 17:56:18 +08:00
{
2024-03-07 03:18:00 +08:00
pixels[i] = color;
2025-03-10 17:56:18 +08:00
}
2024-03-07 03:18:00 +08:00
var result = new Texture2D(width, height);
result.SetPixels(pixels);
result.Apply();
return result;
}
#endregion
}
2024-03-07 21:22:48 +08:00
internal static class RuntimeComponentsUtility
{
public struct WorldData
{
public RuntimeComponentsDropDown addComponentGenericMenu;
2024-03-07 21:22:48 +08:00
public int poolsCount;
public WorldData(RuntimeComponentsDropDown addComponentGenericMenu, int poolsCount)
2024-03-07 21:22:48 +08:00
{
this.addComponentGenericMenu = addComponentGenericMenu;
this.poolsCount = poolsCount;
}
}
//world id
private static Dictionary<EcsWorld, WorldData> _worldDatas = new Dictionary<EcsWorld, WorldData>();
public static RuntimeComponentsDropDown GetAddComponentGenericMenu(EcsWorld world)
2024-03-07 21:22:48 +08:00
{
if (_worldDatas.TryGetValue(world, out WorldData data))
{
if (data.poolsCount != world.PoolsCount)
{
data = CreateWorldData(world);
_worldDatas[world] = data;
}
}
else
{
data = CreateWorldData(world);
_worldDatas[world] = data;
world.AddListener(new Listener(world));
}
return data.addComponentGenericMenu;
}
private static WorldData CreateWorldData(EcsWorld world)
{
2024-09-12 01:35:37 +08:00
IEnumerable<IEcsPool> pools = world.AllPools.ToArray().Where(o => o.IsNullOrDummy() == false);
RuntimeComponentsDropDown genericMenu = new RuntimeComponentsDropDown(pools);
2024-03-07 21:22:48 +08:00
return new WorldData(genericMenu, world.PoolsCount);
}
private class Listener : IEcsWorldEventListener
{
private EcsWorld _world;
public Listener(EcsWorld world)
{
_world = world;
}
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
public void OnWorldDestroy()
{
_worldDatas.Remove(_world);
}
public void OnWorldResize(int newSize) { }
}
}
2024-03-07 03:18:00 +08:00
}
2024-03-07 21:22:48 +08:00
#endif