using UnityEngine; using UnityEditor; using System; using System.Linq; using System.Collections.Generic; [CustomEditor(typeof(SOEditorConfig))] public class SOEditorConfigEditor : Editor { private SerializedProperty _typeNamesProp; private string _searchText = ""; private void OnEnable() { _typeNamesProp = serializedObject.FindProperty("targetTypeNames"); } public override void OnInspectorGUI() { serializedObject.Update(); SOEditorConfig config = (SOEditorConfig)target; GUILayout.Label("已管理的 SO 类型:", EditorStyles.boldLabel); // === 1. 绘制已添加的类型列表 === EditorGUILayout.BeginVertical("box"); for (int i = 0; i < _typeNamesProp.arraySize; i++) { SerializedProperty prop = _typeNamesProp.GetArrayElementAtIndex(i); string typeName = prop.stringValue; EditorGUILayout.BeginHorizontal(); { GUILayout.Label($"{i + 1}. {typeName}", EditorStyles.label); if (GUILayout.Button(EditorGUIUtility.IconContent("TreeEditor.Trash"), EditorStyles.iconButton, GUILayout.Width(25))) { _typeNamesProp.DeleteArrayElementAtIndex(i); break; } } EditorGUILayout.EndHorizontal(); } if (_typeNamesProp.arraySize == 0) { GUILayout.Label("暂无类型,请添加", EditorStyles.centeredGreyMiniLabel); } EditorGUILayout.EndVertical(); GUILayout.Space(10); // === 2. 拖拽区域 (核心修改) === DrawDragDropArea(); GUILayout.Space(10); // === 3. 搜索添加 === GUILayout.Label("或者:搜索添加", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); _searchText = EditorGUILayout.TextField(_searchText, EditorStyles.toolbarSearchField); if (GUILayout.Button("搜索", GUILayout.Width(60))) { ShowTypeSelectorMenu(config); } EditorGUILayout.EndHorizontal(); serializedObject.ApplyModifiedProperties(); } private void DrawDragDropArea() { // 绘制一个虚线框区域 Rect dropArea = GUILayoutUtility.GetRect(0.0f, 60.0f, GUILayout.ExpandWidth(true)); GUI.Box(dropArea, "\n拖拽文件到这里添加\n(支持 .cs 脚本 或 .asset 资源)", EditorStyles.helpBox); Event evt = Event.current; if (evt.type == EventType.DragUpdated || evt.type == EventType.DragPerform) { if (!dropArea.Contains(evt.mousePosition)) return; DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (evt.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (UnityEngine.Object dragged_object in DragAndDrop.objectReferences) { Type typeToAdd = null; // 情况 A: 拖入的是 .cs 脚本文件 if (dragged_object is MonoScript script) { typeToAdd = script.GetClass(); } // 情况 B: 拖入的是 .asset 资源实例 (比如 New Tank.asset) else if (dragged_object is ScriptableObject soInstance) { // 直接获取这个实例的类型 typeToAdd = soInstance.GetType(); } // 执行添加逻辑 if (typeToAdd != null) { // 过滤掉 Config 本身,防止把自己加进去 if (typeToAdd == typeof(SOEditorConfig)) continue; if (typeToAdd.IsSubclassOf(typeof(ScriptableObject))) { AddType(typeToAdd.FullName); } } } } } } private void ShowTypeSelectorMenu(SOEditorConfig config) { GenericMenu menu = new GenericMenu(); var allSoTypes = TypeCache.GetTypesDerivedFrom() .Where(t => !t.IsAbstract && !t.IsGenericType && !t.Namespace.StartsWith("Unity") && !t.Namespace.StartsWith("UnityEditor")) .OrderBy(t => t.Name); foreach (var type in allSoTypes) { if (!string.IsNullOrEmpty(_searchText) && !type.Name.ToLower().Contains(_searchText.ToLower())) continue; string menuPath = string.IsNullOrEmpty(type.Namespace) ? type.Name : $"{type.Namespace}/{type.Name}"; menu.AddItem(new GUIContent(menuPath), config.targetTypeNames.Contains(type.FullName), () => { AddType(type.FullName); }); } menu.ShowAsContext(); } private void AddType(string typeFullName) { serializedObject.Update(); bool exists = false; for (int i = 0; i < _typeNamesProp.arraySize; i++) { if (_typeNamesProp.GetArrayElementAtIndex(i).stringValue == typeFullName) { exists = true; break; } } if (!exists) { _typeNamesProp.InsertArrayElementAtIndex(_typeNamesProp.arraySize); _typeNamesProp.GetArrayElementAtIndex(_typeNamesProp.arraySize - 1).stringValue = typeFullName; serializedObject.ApplyModifiedProperties(); } } }