TH1/Unity/Assets/Editor/ActionInfoDrawer.cs
2026-04-20 22:57:40 +08:00

409 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ActionInfo))]
public class ActionInfoDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var actionIdProp = property.FindPropertyRelative("ActionId");
var actionTypeProp = actionIdProp?.FindPropertyRelative("ActionType");
string actionTypeName = (actionTypeProp != null && actionTypeProp.propertyType == SerializedPropertyType.Enum)
? actionTypeProp.enumDisplayNames[actionTypeProp.enumValueIndex]
: "Unknown";
string secondaryName = "None";
if (actionIdProp != null)
{
SerializedProperty subProp = actionIdProp.Copy();
SerializedProperty endProp = subProp.GetEndProperty();
bool enterChildren = true;
if (subProp.NextVisible(enterChildren))
{
do
{
if (SerializedProperty.EqualContents(subProp, endProp))
break;
if (subProp.propertyType == SerializedPropertyType.Enum &&
subProp.name != "ActionType")
{
if (subProp.enumValueIndex != 0 && subProp.enumValueIndex < subProp.enumDisplayNames.Length)
{
secondaryName = subProp.enumDisplayNames[subProp.enumValueIndex];
break;
}
}
} while (subProp.NextVisible(false));
}
}
// 构造标题不修改原始label创建新的GUIContent
string rawLabel = label.text;
string index = rawLabel.Replace("Element", "").Trim();
GUIContent newLabel = new GUIContent($"[{actionTypeName}: {secondaryName}] {index}");
// Foldout
property.isExpanded = EditorGUI.Foldout(
new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight),
property.isExpanded,
newLabel
);
// 展开所有字段
if (property.isExpanded)
{
EditorGUI.indentLevel++;
float y = position.y + EditorGUIUtility.singleLineHeight;
SerializedProperty childProp = property.Copy();
SerializedProperty end = childProp.GetEndProperty();
if (childProp.NextVisible(true))
{
do
{
if (SerializedProperty.EqualContents(childProp, end))
break;
float h = EditorGUI.GetPropertyHeight(childProp, true);
EditorGUI.PropertyField(new Rect(position.x, y, position.width, h), childProp, true);
y += h + EditorGUIUtility.standardVerticalSpacing;
} while (childProp.NextVisible(false));
}
EditorGUI.indentLevel--;
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float height = EditorGUIUtility.singleLineHeight;
if (property.isExpanded)
{
SerializedProperty childProp = property.Copy();
SerializedProperty end = childProp.GetEndProperty();
if (childProp.NextVisible(true))
{
do
{
if (SerializedProperty.EqualContents(childProp, end))
break;
height += EditorGUI.GetPropertyHeight(childProp, true) + EditorGUIUtility.standardVerticalSpacing;
} while (childProp.NextVisible(false));
}
}
return height;
}
}
// =================================== ActionDataAssets 自定义编辑器(带搜索功能) ===================================
[CustomEditor(typeof(ActionDataAssets))]
public class ActionDataAssetsEditor : Editor
{
private string _searchFilter = "";
private List<int> _filteredIndices = new List<int>();
private SerializedProperty _actionListProperty;
private Vector2 _scrollPosition;
private bool _isSearching = false;
private void OnEnable()
{
_actionListProperty = serializedObject.FindProperty("ActionList");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
// 绘制默认字段排除ActionList
DrawPropertiesExcluding(serializedObject, "ActionList");
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("行动列表", EditorStyles.boldLabel);
// 新增Action按钮搜索模式下禁用
using (new EditorGUI.DisabledGroupScope(_isSearching))
{
if (GUILayout.Button("新增 Action", GUILayout.Height(30)))
{
_actionListProperty.arraySize++;
var newElement = _actionListProperty.GetArrayElementAtIndex(_actionListProperty.arraySize - 1);
newElement.isExpanded = true;
serializedObject.ApplyModifiedProperties();
_scrollPosition.y = float.MaxValue;
}
}
EditorGUILayout.Space(5);
// 搜索框
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("搜索:", GUILayout.Width(100));
string newFilter = EditorGUILayout.TextField(_searchFilter);
if (GUILayout.Button("清除", GUILayout.Width(50)) && !string.IsNullOrEmpty(_searchFilter))
{
newFilter = "";
GUI.FocusControl(null);
}
EditorGUILayout.EndHorizontal();
// 检测搜索变化
if (newFilter != _searchFilter)
{
_searchFilter = newFilter;
_isSearching = !string.IsNullOrEmpty(_searchFilter);
UpdateFilteredIndices();
}
// 显示筛选状态
if (_isSearching)
{
EditorGUILayout.LabelField($"筛选结果: {_filteredIndices.Count} 个行动", EditorStyles.miniLabel);
}
EditorGUILayout.Space(5);
// 绘制ActionList
if (_actionListProperty != null)
{
_actionListProperty.isExpanded = EditorGUILayout.Foldout(
_actionListProperty.isExpanded,
$"Action List ({(_isSearching ? _filteredIndices.Count : _actionListProperty.arraySize)} items)",
true
);
if (_actionListProperty.isExpanded)
{
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.Height(500));
if (_isSearching)
{
if (_filteredIndices.Count == 0)
{
EditorGUILayout.HelpBox("没有找到匹配的行动", MessageType.Info);
}
else
{
foreach (int index in _filteredIndices)
{
DrawActionItem(index, false);
}
}
}
else
{
DrawActionListReverse();
}
EditorGUILayout.EndScrollView();
}
}
serializedObject.ApplyModifiedProperties();
}
private void DrawActionItem(int index, bool showDelete)
{
SerializedProperty element = _actionListProperty.GetArrayElementAtIndex(index);
string displayName = GetActionDisplayName(element);
EditorGUILayout.BeginVertical(GUI.skin.box);
EditorGUILayout.BeginHorizontal();
string title = $"[{index}] {displayName}";
bool wasExpanded = element.isExpanded;
element.isExpanded = EditorGUILayout.Foldout(wasExpanded, title, true);
// 删除按钮(非搜索模式下显示)
if (showDelete)
{
if (GUILayout.Button("-", GUILayout.Width(25), GUILayout.Height(18)))
{
_actionListProperty.DeleteArrayElementAtIndex(index);
serializedObject.ApplyModifiedProperties();
GUIUtility.ExitGUI();
return;
}
}
EditorGUILayout.EndHorizontal();
// 用切换前的值决定是否绘制子属性确保Layout和Repaint阶段控件数一致
if (wasExpanded)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(element, GUIContent.none, true);
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
private void DrawActionListReverse()
{
int count = _actionListProperty.arraySize;
for (int i = count - 1; i >= 0; i--)
{
DrawActionItem(i, true);
}
}
private void UpdateFilteredIndices()
{
_filteredIndices.Clear();
if (_actionListProperty == null || string.IsNullOrEmpty(_searchFilter))
return;
string filter = _searchFilter.ToLower();
int count = _actionListProperty.arraySize;
for (int i = 0; i < count; i++)
{
SerializedProperty element = _actionListProperty.GetArrayElementAtIndex(i);
if (MatchesFilter(element, filter))
_filteredIndices.Add(i);
}
}
private bool MatchesFilter(SerializedProperty element, string filter)
{
string displayName = GetActionDisplayName(element);
if (displayName.ToLower().Contains(filter))
return true;
// 搜索ActionId中的所有字段
var actionIdProp = element.FindPropertyRelative("ActionId");
if (actionIdProp != null)
{
SerializedProperty iterator = actionIdProp.Copy();
SerializedProperty end = iterator.GetEndProperty();
if (iterator.NextVisible(true))
{
do
{
if (SerializedProperty.EqualContents(iterator, end))
break;
// 搜索枚举类型的显示名称
if (iterator.propertyType == SerializedPropertyType.Enum)
{
if (iterator.enumValueIndex >= 0 && iterator.enumValueIndex < iterator.enumDisplayNames.Length)
{
string enumName = iterator.enumDisplayNames[iterator.enumValueIndex];
if (enumName.ToLower().Contains(filter))
return true;
}
}
// 搜索string/int/uint等基础类型
else if (iterator.propertyType == SerializedPropertyType.String &&
!string.IsNullOrEmpty(iterator.stringValue))
{
if (iterator.stringValue.ToLower().Contains(filter))
return true;
}
else if (iterator.propertyType == SerializedPropertyType.Integer)
{
if (iterator.intValue.ToString() == filter)
return true;
}
} while (iterator.NextVisible(false));
}
}
// 搜索ActionInfo中的字段
var actionNameProp = element.FindPropertyRelative("ActionName");
if (actionNameProp != null && !string.IsNullOrEmpty(actionNameProp.stringValue))
{
if (actionNameProp.stringValue.ToLower().Contains(filter))
return true;
}
var descProp = element.FindPropertyRelative("Desc");
if (descProp != null && !string.IsNullOrEmpty(descProp.stringValue))
{
if (descProp.stringValue.ToLower().Contains(filter))
return true;
}
return false;
}
private string GetActionDisplayName(SerializedProperty element)
{
var actionIdProp = element.FindPropertyRelative("ActionId");
if (actionIdProp == null)
return "Unknown";
var actionTypeProp = actionIdProp.FindPropertyRelative("ActionType");
string actionTypeName = actionTypeProp?.enumDisplayNames[actionTypeProp.enumValueIndex] ?? "Unknown";
// 查找首个非None/0的参数
string secondaryParam = "";
SerializedProperty iterator = actionIdProp.Copy();
SerializedProperty end = iterator.GetEndProperty();
if (iterator.NextVisible(true))
{
do
{
if (SerializedProperty.EqualContents(iterator, end))
break;
if (iterator.name == "ActionType")
continue;
// 检查枚举类型
if (iterator.propertyType == SerializedPropertyType.Enum)
{
if (iterator.enumValueIndex != 0 &&
iterator.enumValueIndex < iterator.enumDisplayNames.Length)
{
string paramName = iterator.enumDisplayNames[iterator.enumValueIndex];
if (paramName != "None")
{
secondaryParam = paramName;
break;
}
}
}
// 检查整数类型非0
else if (iterator.propertyType == SerializedPropertyType.Integer)
{
if (iterator.intValue != 0)
{
secondaryParam = iterator.name + ":" + iterator.intValue;
break;
}
}
// 检查uint/uint32类型
else if (iterator.propertyType == SerializedPropertyType.Integer && iterator.name == "UnitLevel")
{
// uint类型的判断通过value不为0
if ((uint)iterator.intValue != 0)
{
secondaryParam = iterator.name + ":" + iterator.intValue;
break;
}
}
} while (iterator.NextVisible(false));
}
if (!string.IsNullOrEmpty(secondaryParam) && secondaryParam != "None")
return $"{actionTypeName} [{secondaryParam}]";
return actionTypeName;
}
}