2025-02-07 16:05:13 +08:00
|
|
|
|
using System;
|
2025-11-18 11:27:53 +08:00
|
|
|
|
using System.Reflection;
|
2025-02-07 16:05:13 +08:00
|
|
|
|
using AlicizaX.AnimationFlow.Runtime;
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UIElements;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AlicizaX.AnimationFlow.Editor
|
|
|
|
|
|
{
|
|
|
|
|
|
public class GraphInspector : VisualElement
|
|
|
|
|
|
{
|
2025-11-18 11:27:53 +08:00
|
|
|
|
private ActionNode currentActionNode;
|
|
|
|
|
|
private NodeView currentNodeView;
|
2025-02-07 16:05:13 +08:00
|
|
|
|
|
|
|
|
|
|
public void DrawNode(NodeView nodeView)
|
|
|
|
|
|
{
|
|
|
|
|
|
Clear();
|
2025-11-18 11:27:53 +08:00
|
|
|
|
if (nodeView?.actionNode == null)
|
2025-02-07 16:05:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 11:27:53 +08:00
|
|
|
|
currentActionNode = nodeView.actionNode;
|
|
|
|
|
|
currentNodeView = nodeView;
|
2025-02-07 16:05:13 +08:00
|
|
|
|
|
|
|
|
|
|
var imguiContainer = new IMGUIContainer(() =>
|
|
|
|
|
|
{
|
2025-11-18 11:27:53 +08:00
|
|
|
|
if (currentActionNode == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
|
|
|
|
|
|
|
|
DrawActionNodeInspector();
|
|
|
|
|
|
|
|
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
2025-02-07 16:05:13 +08:00
|
|
|
|
{
|
2025-11-18 11:27:53 +08:00
|
|
|
|
currentNodeView?.RefreshState();
|
2025-02-07 16:05:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
Add(imguiContainer);
|
2025-11-18 11:27:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DrawActionNodeInspector()
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorGUILayout.BeginVertical(GUI.skin.box);
|
|
|
|
|
|
|
|
|
|
|
|
DrawQualifiedFields(currentActionNode);
|
|
|
|
|
|
|
|
|
|
|
|
EditorGUILayout.EndVertical();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DrawQualifiedFields(object targetObject)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (targetObject == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
Type objectType = targetObject.GetType();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有实例字段(公共和非公共)
|
|
|
|
|
|
var allFields = objectType.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var field in allFields)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 跳过不应该绘制的字段
|
|
|
|
|
|
if (ShouldSkipField(field)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
DrawFieldViaReflection(targetObject, field);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool ShouldSkipField(FieldInfo field)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 跳过编译器生成的字段
|
|
|
|
|
|
if (field.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false))
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过非序列化字段(但如果标记了SerializeField,则仍然绘制)
|
|
|
|
|
|
if (field.IsDefined(typeof(System.NonSerializedAttribute), false) && !field.IsDefined(typeof(SerializeField), false))
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过静态字段
|
|
|
|
|
|
if (field.IsStatic)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过在ActionNode基类中声明的字段
|
|
|
|
|
|
if (field.DeclaringType == typeof(ActionNode))
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过受保护字段(protected)
|
|
|
|
|
|
if (field.IsFamily)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// 关键修改:只绘制公共字段,或者私有但包含SerializeField特性的字段
|
|
|
|
|
|
if (!field.IsPublic && !field.IsDefined(typeof(SerializeField), false))
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DrawFieldViaReflection(object targetObject, FieldInfo field)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var fieldValue = field.GetValue(targetObject);
|
|
|
|
|
|
var fieldType = field.FieldType;
|
|
|
|
|
|
string displayName = GetFieldDisplayName(field);
|
|
|
|
|
|
|
|
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
|
|
|
|
|
|
|
|
|
|
var newValue = DrawFieldByType(displayName, fieldValue, fieldType);
|
|
|
|
|
|
|
|
|
|
|
|
if (!Equals(newValue, fieldValue))
|
|
|
|
|
|
{
|
|
|
|
|
|
field.SetValue(targetObject, newValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorGUILayout.LabelField(field.Name, $"绘制错误: {e.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string GetFieldDisplayName(FieldInfo field)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查是否有Header特性
|
|
|
|
|
|
var headerAttr = field.GetCustomAttribute<HeaderAttribute>();
|
|
|
|
|
|
if (headerAttr != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return headerAttr.header;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将驼峰命名转换为空格分隔的友好名称
|
|
|
|
|
|
return ObjectNames.NicifyVariableName(field.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private object DrawFieldByType(string label, object value, Type fieldType)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (fieldType == typeof(string))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.TextField(label, (string)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(int))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.IntField(label, (int)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(float))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.FloatField(label, (float)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(bool))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.Toggle(label, (bool)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(Vector2))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.Vector2Field(label, (Vector2)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(Vector3))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.Vector3Field(label, (Vector3)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(Color))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.ColorField(label, (Color)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType.IsEnum)
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.EnumPopup(label, (Enum)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fieldType == typeof(UnityEngine.Object) || fieldType.IsSubclassOf(typeof(UnityEngine.Object)))
|
|
|
|
|
|
{
|
|
|
|
|
|
return EditorGUILayout.ObjectField(label, (UnityEngine.Object)value, fieldType, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 对于不支持的类型,显示为只读标签
|
|
|
|
|
|
EditorGUILayout.LabelField(label, value?.ToString() ?? "null");
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
2025-02-07 16:05:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-18 11:27:53 +08:00
|
|
|
|
}
|