DragonECS-Unity/src/Editor/EditorUtility.cs

334 lines
11 KiB
C#
Raw Normal View History

2024-03-03 19:59:39 +08:00
#if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
2024-03-03 22:46:26 +08:00
using System.Text;
2024-03-03 19:59:39 +08:00
using UnityEditor;
using UnityEngine;
namespace DCFApixels.DragonECS.Unity.Editors
{
2024-03-03 22:46:26 +08:00
internal static class EcsUnityEditorUtility
2024-03-03 19:59:39 +08:00
{
2024-03-03 22:46:26 +08:00
public static string TransformFieldName(string name)
2024-03-03 19:59:39 +08:00
{
2024-03-03 22:46:26 +08:00
if (name.Length <= 0)
2024-03-03 19:59:39 +08:00
{
2024-03-03 22:46:26 +08:00
return name;
2024-03-03 19:59:39 +08:00
}
2024-03-03 22:46:26 +08:00
StringBuilder b = new StringBuilder();
bool nextWorld = true;
bool prewIsUpper = false;
for (int i = 0; i < name.Length; i++)
2024-03-03 19:59:39 +08:00
{
2024-03-03 22:46:26 +08:00
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(' ');
2024-03-04 03:00:45 +08:00
nextWorld = true;
2024-03-03 22:46:26 +08:00
}
}
2024-03-04 03:00:45 +08:00
if (nextWorld)
{
b.Append(char.ToUpper(c));
}
2024-03-03 22:46:26 +08:00
else
{
2024-03-04 03:00:45 +08:00
b.Append(c);
2024-03-03 22:46:26 +08:00
}
2024-03-04 03:00:45 +08:00
nextWorld = false;
2024-03-03 22:46:26 +08:00
prewIsUpper = isUpper;
2024-03-03 19:59:39 +08:00
}
2024-03-03 22:46:26 +08:00
return b.ToString();
2024-03-03 19:59:39 +08:00
}
}
2024-03-03 22:46:26 +08:00
2024-03-03 19:59:39 +08:00
2024-03-04 07:38:38 +08:00
internal static class EcsGUI
2024-03-03 19:59:39 +08:00
{
2024-03-04 07:38:38 +08:00
internal readonly static Color GrayColor = new Color32(100, 100, 100, 255);
internal readonly static Color GreenColor = new Color32(75, 255, 0, 255);
internal readonly static Color RedColor = new Color32(255, 0, 75, 255);
2024-03-03 19:59:39 +08:00
2024-03-04 07:38:38 +08:00
//private static GUIStyle _grayStyle;
//private static GUIStyle _greenStyle;
//private static GUIStyle _redStyle;
2024-03-03 19:59:39 +08:00
private static GUILayoutOption[] _defaultParams;
private static bool _isInit = false;
private static void Init()
{
if (_isInit)
{
return;
}
_defaultParams = new GUILayoutOption[] { GUILayout.ExpandWidth(true) };
2024-03-04 07:38:38 +08:00
//_grayStyle = EcsEditor.GetStyle(GrayColor);
//_greenStyle = EcsEditor.GetStyle(GreenColor);
//_redStyle = EcsEditor.GetStyle(RedColor);
2024-03-03 19:59:39 +08:00
_isInit = true;
}
2024-03-04 07:38:38 +08:00
//private const string CONNECTED = "Connected";
//private const string NOT_CONNECTED = "Not connected";
//private const string UNDETERMINED_CONNECTED = "---";
//public static void DrawConnectStatus(Rect position, bool status)
//{
// Init();
// if (status)
// {
// GUI.Box(position, CONNECTED, _greenStyle);
// }
// else
// {
// GUI.Box(position, NOT_CONNECTED, _redStyle);
// }
//}
//
//public static void DrawUndeterminedConnectStatus(Rect position)
//{
// Init();
// GUI.Box(position, UNDETERMINED_CONNECTED, _grayStyle);
//}
2024-03-03 19:59:39 +08:00
public static class Layout
{
2024-03-04 07:38:38 +08:00
//public static void DrawConnectStatus(bool status, params GUILayoutOption[] options)
//{
// Init();
// if (options == null || options.Length <= 0)
// {
// options = _defaultParams;
// }
// GUILayout.Box("", options);
// Rect lastRect = GUILayoutUtility.GetLastRect();
// Color color = status ? GreenColor : RedColor;
// string text = status ? CONNECTED : NOT_CONNECTED;
// color.a = 0.6f;
// EditorGUI.DrawRect(lastRect, color);
// GUI.Box(lastRect, text);
//}
//public static void DrawUndeterminedConnectStatus(params GUILayoutOption[] options)
//{
// Init();
// if (options == null || options.Length <= 0)
// {
// options = _defaultParams;
// }
// GUILayout.Box(UNDETERMINED_CONNECTED, _grayStyle, options);
//}
2024-03-03 19:59:39 +08:00
public static void DrawComponents(entlong entity)
{
if (entity.TryUnpack(out int entityID, out EcsWorld world))
{
DrawComponents(entityID, world);
}
}
public static void DrawComponents(int entityID, EcsWorld world)
{
var componentTypeIDs = world.GetComponentTypeIDs(entityID);
2024-03-04 07:38:38 +08:00
GUILayout.BeginVertical(EcsEditor.GetStyle(Color.black, 0.2f));
2024-03-03 19:59:39 +08:00
foreach (var componentTypeID in componentTypeIDs)
{
var pool = world.GetPool(componentTypeID);
{
2024-03-04 07:38:38 +08:00
DrawComponent(entityID, pool);
2024-03-03 19:59:39 +08:00
}
}
2024-03-04 07:38:38 +08:00
GUILayout.EndVertical();
2024-03-03 19:59:39 +08:00
}
private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
2024-03-04 07:38:38 +08:00
private static void DrawComponent(int entityID, IEcsPool pool)
2024-03-03 19:59:39 +08:00
{
object data = pool.GetRaw(entityID);
var meta = data.GetMeta();
Color panelColor = meta.Color.ToUnityColor();
GUILayout.BeginVertical(EcsEditor.GetStyle(panelColor, 0.22f));
EditorGUI.BeginChangeCheck();
2024-03-04 03:00:45 +08:00
Type componentType = pool.ComponentType;
ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType);
bool changed = DrawData(componentType, new GUIContent(meta.Name), expandMatrix, data, out object resultData);
2024-03-03 19:59:39 +08:00
if (changed)
{
pool.SetRaw(entityID, resultData);
}
GUILayout.EndVertical();
GUILayout.Space(2f);
}
2024-03-04 03:00:45 +08:00
private static bool DrawData(Type fieldType, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData)
2024-03-03 19:59:39 +08:00
{
Type type = data.GetType();
2024-03-04 07:38:38 +08:00
UnityEngine.Object uobj = data as UnityEngine.Object;
2024-03-04 03:00:45 +08:00
ref bool isExpanded = ref expandMatrix.Down();
2024-03-04 07:38:38 +08:00
bool changed = false;
outData = data;
2024-03-03 22:46:26 +08:00
2024-03-04 07:38:38 +08:00
if (uobj == null && (type.IsGenericType || !type.IsSerializable))
2024-03-03 19:59:39 +08:00
{
2024-03-04 03:00:45 +08:00
isExpanded = EditorGUILayout.Foldout(isExpanded, label);
if (isExpanded)
2024-03-03 19:59:39 +08:00
{
2024-03-03 22:46:26 +08:00
EditorGUI.indentLevel++;
foreach (var field in type.GetFields(fieldFlags))
2024-03-03 19:59:39 +08:00
{
2024-03-03 22:46:26 +08:00
GUIContent subLabel = new GUIContent(EcsUnityEditorUtility.TransformFieldName(field.Name));
2024-03-04 03:00:45 +08:00
if (DrawData(field.FieldType, subLabel, expandMatrix, field.GetValue(data), out object fieldData))
2024-03-03 22:46:26 +08:00
{
field.SetValue(data, fieldData);
2024-03-04 07:38:38 +08:00
outData = fieldData;
changed = true;
2024-03-03 22:46:26 +08:00
}
2024-03-03 19:59:39 +08:00
}
2024-03-03 22:46:26 +08:00
EditorGUI.indentLevel--;
2024-03-03 19:59:39 +08:00
}
}
else
{
2024-03-03 22:46:26 +08:00
EditorGUI.BeginChangeCheck();
2024-03-04 03:00:45 +08:00
WrapperBase w = uobj == null ? RefEditorWrapper.Take(data) : UnityObjEditorWrapper.Take(uobj);
2024-03-03 19:59:39 +08:00
2024-03-04 03:00:45 +08:00
w.IsExpanded = isExpanded;
2024-03-03 22:46:26 +08:00
EditorGUILayout.PropertyField(w.Property, label, true);
2024-03-04 03:00:45 +08:00
isExpanded = w.IsExpanded;
2024-03-03 22:46:26 +08:00
if (EditorGUI.EndChangeCheck())
{
w.SO.ApplyModifiedProperties();
outData = w.Data;
2024-03-04 07:38:38 +08:00
changed = true;
2024-03-03 19:59:39 +08:00
}
}
2024-03-04 07:38:38 +08:00
expandMatrix.Up();
return changed;
2024-03-03 19:59:39 +08:00
}
}
}
[InitializeOnLoad]
public static class EcsEditor
{
static EcsEditor()
{
colorBoxeStyles = new SparseArray<GUIStyle>();
}
private static SparseArray<GUIStyle> colorBoxeStyles = new SparseArray<GUIStyle>();
public static GUIStyle GetStyle(Color color, float alphaMultiplier)
{
color.a *= alphaMultiplier;
return GetStyle(color);
}
public static GUIStyle GetStyle(Color32 color32)
{
int colorCode = new Color32Union(color32).colorCode;
if (colorBoxeStyles.TryGetValue(colorCode, out GUIStyle style))
{
if (style == null || style.normal.background == null)
{
style = CreateStyle(color32, colorCode);
colorBoxeStyles[colorCode] = style;
}
return style;
}
style = CreateStyle(color32, colorCode);
colorBoxeStyles.Add(colorCode, style);
return style;
}
private static GUIStyle CreateStyle(Color32 color32, int colorCode)
{
GUIStyle result = new GUIStyle(GUI.skin.box);
Color componentColor = color32;
Texture2D texture2D = CreateTexture(2, 2, componentColor);
result.hover.background = texture2D;
result.focused.background = texture2D;
result.active.background = texture2D;
result.normal.background = texture2D;
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)
pixels[i] = color;
var result = new Texture2D(width, height);
result.SetPixels(pixels);
result.Apply();
return result;
}
#region Utils
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)]
private readonly ref struct Color32Union
{
[FieldOffset(0)]
public readonly int colorCode;
[FieldOffset(0)]
public readonly byte r;
[FieldOffset(1)]
public readonly byte g;
[FieldOffset(2)]
public readonly byte b;
[FieldOffset(3)]
public readonly byte a;
public Color32Union(byte r, byte g, byte b, byte a) : this()
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
public Color32Union(Color32 color) : this()
{
r = color.r;
g = color.g;
b = color.b;
a = color.a;
}
}
#endregion
}
public static class ReflectionExtensions
{
public static bool TryGetAttribute<T>(this MemberInfo self, out T attrbiute) where T : Attribute
{
attrbiute = self.GetCustomAttribute<T>();
return attrbiute != null;
}
public static bool HasAttribute<T>(this MemberInfo self) where T : Attribute
{
return self.GetCustomAttribute<T>() != null;
}
}
}
#endif