using UnityEngine; 
 | 
using UnityEditor; 
 | 
using System.Collections.Generic; 
 | 
using System.Linq; 
 | 
using System.Reflection; 
 | 
using System; 
 | 
  
 | 
/// <summary> 
 | 
/// 扫描 GameObject 中的无效脚本的编辑器工具 
 | 
/// </summary> 
 | 
public class InvalidScriptScanner : EditorWindow 
 | 
{ 
 | 
    // 扫描模式枚举 
 | 
    private enum ScanMode 
 | 
    { 
 | 
        Basic,      // 基本扫描 
 | 
        Advanced,   // 高级扫描 
 | 
        Deep        // 深度扫描 
 | 
    } 
 | 
     
 | 
    // 当前扫描模式 
 | 
    private static ScanMode currentScanMode = ScanMode.Advanced; 
 | 
     
 | 
    /// <summary> 
 | 
    /// 添加右键菜单项 
 | 
    /// </summary> 
 | 
    [MenuItem("GameObject/扫描无效脚本", false, 20)] 
 | 
    private static void ScanInvalidScripts() 
 | 
    { 
 | 
        GameObject selectedObject = Selection.activeGameObject; 
 | 
        if (selectedObject == null) 
 | 
        { 
 | 
            EditorUtility.DisplayDialog("错误", "请先选择一个游戏对象", "确定"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        // 使用改进的方法检测无效脚本 
 | 
        List<int> invalidScriptIndices = FindInvalidScripts(selectedObject); 
 | 
  
 | 
        if (invalidScriptIndices.Count > 0) 
 | 
        { 
 | 
            // 找到了无效脚本 
 | 
            int invalidScriptIndex = invalidScriptIndices[0]; // 获取第一个无效脚本 
 | 
            Debug.LogWarning($"在游戏对象 '{selectedObject.name}' 上发现无效脚本,位于组件索引 {invalidScriptIndex}"); 
 | 
             
 | 
            // 高亮显示该对象 
 | 
            Selection.activeGameObject = selectedObject; 
 | 
             
 | 
            // 打开检查器并滚动到该组件 
 | 
            EditorGUIUtility.PingObject(selectedObject); 
 | 
             
 | 
            // 显示对话框 
 | 
            if (EditorUtility.DisplayDialog("发现无效脚本",  
 | 
                $"在游戏对象 '{selectedObject.name}' 上发现无效脚本,位于组件索引 {invalidScriptIndex}。\n\n是否要移除该无效脚本?",  
 | 
                "移除", "取消")) 
 | 
            { 
 | 
                // 移除无效脚本 
 | 
                RemoveInvalidScript(selectedObject, invalidScriptIndex); 
 | 
            } 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            // 未找到无效脚本,尝试更深层次的扫描 
 | 
            if (currentScanMode != ScanMode.Deep) 
 | 
            { 
 | 
                if (EditorUtility.DisplayDialog("未找到无效脚本",  
 | 
                    $"在游戏对象 '{selectedObject.name}' 上未发现无效脚本。\n\n是否要尝试深度扫描?这可能需要更长时间。",  
 | 
                    "深度扫描", "取消")) 
 | 
                { 
 | 
                    // 临时切换到深度扫描模式 
 | 
                    ScanMode previousMode = currentScanMode; 
 | 
                    currentScanMode = ScanMode.Deep; 
 | 
                     
 | 
                    // 重新扫描 
 | 
                    invalidScriptIndices = FindInvalidScripts(selectedObject); 
 | 
                     
 | 
                    // 恢复之前的扫描模式 
 | 
                    currentScanMode = previousMode; 
 | 
                     
 | 
                    if (invalidScriptIndices.Count > 0) 
 | 
                    { 
 | 
                        // 找到了无效脚本 
 | 
                        int invalidScriptIndex = invalidScriptIndices[0]; 
 | 
                        Debug.LogWarning($"深度扫描:在游戏对象 '{selectedObject.name}' 上发现无效脚本,位于组件索引 {invalidScriptIndex}"); 
 | 
                         
 | 
                        // 显示对话框 
 | 
                        if (EditorUtility.DisplayDialog("深度扫描发现无效脚本",  
 | 
                            $"在游戏对象 '{selectedObject.name}' 上发现无效脚本,位于组件索引 {invalidScriptIndex}。\n\n是否要移除该无效脚本?",  
 | 
                            "移除", "取消")) 
 | 
                        { 
 | 
                            // 移除无效脚本 
 | 
                            RemoveInvalidScript(selectedObject, invalidScriptIndex); 
 | 
                        } 
 | 
                    } 
 | 
                    else 
 | 
                    { 
 | 
                        // 深度扫描也未找到无效脚本 
 | 
                        EditorUtility.DisplayDialog("深度扫描完成", $"在游戏对象 '{selectedObject.name}' 上未发现无效脚本。", "确定"); 
 | 
                    } 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    // 用户取消深度扫描 
 | 
                    EditorUtility.DisplayDialog("扫描完成", $"在游戏对象 '{selectedObject.name}' 上未发现无效脚本。", "确定"); 
 | 
                } 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                // 已经是深度扫描模式 
 | 
                EditorUtility.DisplayDialog("扫描完成", $"在游戏对象 '{selectedObject.name}' 上未发现无效脚本。", "确定"); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 查找无效脚本 
 | 
    /// </summary> 
 | 
    /// <param name="gameObject">要检查的游戏对象</param> 
 | 
    /// <returns>无效脚本的索引列表</returns> 
 | 
    private static List<int> FindInvalidScripts(GameObject gameObject) 
 | 
    { 
 | 
        List<int> invalidIndices = new List<int>(); 
 | 
         
 | 
        // 检查游戏对象是否有效 
 | 
        if (gameObject == null) 
 | 
            return invalidIndices; 
 | 
             
 | 
        // 方法1:使用 SerializedObject 检查组件 
 | 
        SerializedObject serializedObject = new SerializedObject(gameObject); 
 | 
        SerializedProperty componentsProperty = serializedObject.FindProperty("m_Component"); 
 | 
         
 | 
        for (int i = 0; i < componentsProperty.arraySize; i++) 
 | 
        { 
 | 
            SerializedProperty componentProperty = componentsProperty.GetArrayElementAtIndex(i); 
 | 
            SerializedProperty scriptProperty = componentProperty.FindPropertyRelative("component"); 
 | 
             
 | 
            // 检查脚本引用是否有效 
 | 
            if (scriptProperty.objectReferenceValue == null || scriptProperty.objectReferenceInstanceIDValue == 0) 
 | 
            { 
 | 
                invalidIndices.Add(i); 
 | 
                continue; 
 | 
            } 
 | 
             
 | 
            // 额外检查:尝试获取实际组件并检查其类型 
 | 
            UnityEngine.Object scriptObject = scriptProperty.objectReferenceValue; 
 | 
            if (scriptObject != null) 
 | 
            { 
 | 
                // 检查脚本是否为缺失或损坏的 MonoScript 
 | 
                MonoScript monoScript = scriptObject as MonoScript; 
 | 
                if (monoScript != null && monoScript.GetClass() == null) 
 | 
                { 
 | 
                    invalidIndices.Add(i); 
 | 
                    continue; 
 | 
                } 
 | 
                 
 | 
                // 高级扫描:检查组件是否可以正确序列化 
 | 
                if (currentScanMode >= ScanMode.Advanced) 
 | 
                { 
 | 
                    try 
 | 
                    { 
 | 
                        // 尝试获取组件的类型 
 | 
                        Type componentType = scriptObject.GetType(); 
 | 
                        if (componentType == null || componentType.ToString().Contains("Missing") || componentType.ToString().Contains("missing")) 
 | 
                        { 
 | 
                            invalidIndices.Add(i); 
 | 
                            continue; 
 | 
                        } 
 | 
                    } 
 | 
                    catch (Exception) 
 | 
                    { 
 | 
                        // 如果获取类型时出现异常,可能是无效脚本 
 | 
                        invalidIndices.Add(i); 
 | 
                        continue; 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
         
 | 
        // 方法2:使用 GetComponents 检查组件(可能会检测到一些方法1漏掉的情况) 
 | 
        Component[] components = gameObject.GetComponents<Component>(); 
 | 
        for (int i = 0; i < components.Length; i++) 
 | 
        { 
 | 
            if (components[i] == null) 
 | 
            { 
 | 
                // 检查这个索引是否已经在列表中 
 | 
                if (!invalidIndices.Contains(i)) 
 | 
                { 
 | 
                    invalidIndices.Add(i); 
 | 
                } 
 | 
                continue; 
 | 
            } 
 | 
             
 | 
            // 深度扫描:尝试访问组件的一些属性,看是否会抛出异常 
 | 
            if (currentScanMode == ScanMode.Deep) 
 | 
            { 
 | 
                try 
 | 
                { 
 | 
                    // 尝试获取组件的名称和启用状态 
 | 
                    string name = components[i].name; 
 | 
                    bool enabled = false; 
 | 
                     
 | 
                    // 尝试获取启用状态(只对 Behaviour 类型有效) 
 | 
                    if (components[i] is Behaviour behaviour) 
 | 
                    { 
 | 
                        enabled = behaviour.enabled; 
 | 
                    } 
 | 
                     
 | 
                    // 尝试序列化组件 
 | 
                    SerializedObject testSerializedObject = new SerializedObject(components[i]); 
 | 
                    SerializedProperty iterator = testSerializedObject.GetIterator(); 
 | 
                    bool hasProperties = iterator.NextVisible(true); 
 | 
                     
 | 
                    // 如果无法获取任何属性,可能是无效脚本 
 | 
                    if (!hasProperties && !invalidIndices.Contains(i)) 
 | 
                    { 
 | 
                        invalidIndices.Add(i); 
 | 
                    } 
 | 
                } 
 | 
                catch (Exception) 
 | 
                { 
 | 
                    // 如果访问组件属性时出现异常,可能是无效脚本 
 | 
                    if (!invalidIndices.Contains(i)) 
 | 
                    { 
 | 
                        invalidIndices.Add(i); 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
         
 | 
        // 检查隐藏的游戏对象(即使是隐藏的,也可能包含无效脚本) 
 | 
        if (currentScanMode >= ScanMode.Advanced) 
 | 
        { 
 | 
            // 获取所有隐藏的子对象 
 | 
            Transform[] allChildren = gameObject.GetComponentsInChildren<Transform>(true); 
 | 
            foreach (Transform child in allChildren) 
 | 
            { 
 | 
                // 跳过当前对象(因为已经检查过了) 
 | 
                if (child.gameObject == gameObject) 
 | 
                    continue; 
 | 
                     
 | 
                // 如果子对象是隐藏的或者父对象是隐藏的,单独检查它 
 | 
                if (!child.gameObject.activeInHierarchy) 
 | 
                { 
 | 
                    // 递归检查隐藏的子对象 
 | 
                    List<int> childInvalidIndices = FindInvalidScriptsInHiddenObject(child.gameObject); 
 | 
                    if (childInvalidIndices.Count > 0) 
 | 
                    { 
 | 
                        // 如果在隐藏的子对象中找到了无效脚本,添加到结果中 
 | 
                        // 注意:这里我们只是记录了索引,实际上需要在UI中显示完整路径 
 | 
                        foreach (int index in childInvalidIndices) 
 | 
                        { 
 | 
                            if (!invalidIndices.Contains(index)) 
 | 
                            { 
 | 
                                invalidIndices.Add(index); 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
         
 | 
        return invalidIndices; 
 | 
    } 
 | 
     
 | 
    /// <summary> 
 | 
    /// 在隐藏的游戏对象中查找无效脚本 
 | 
    /// </summary> 
 | 
    private static List<int> FindInvalidScriptsInHiddenObject(GameObject gameObject) 
 | 
    { 
 | 
        List<int> invalidIndices = new List<int>(); 
 | 
         
 | 
        // 检查游戏对象是否有效 
 | 
        if (gameObject == null) 
 | 
            return invalidIndices; 
 | 
             
 | 
        // 使用 SerializedObject 检查组件 
 | 
        SerializedObject serializedObject = new SerializedObject(gameObject); 
 | 
        SerializedProperty componentsProperty = serializedObject.FindProperty("m_Component"); 
 | 
         
 | 
        for (int i = 0; i < componentsProperty.arraySize; i++) 
 | 
        { 
 | 
            SerializedProperty componentProperty = componentsProperty.GetArrayElementAtIndex(i); 
 | 
            SerializedProperty scriptProperty = componentProperty.FindPropertyRelative("component"); 
 | 
             
 | 
            // 检查脚本引用是否有效 
 | 
            if (scriptProperty.objectReferenceValue == null || scriptProperty.objectReferenceInstanceIDValue == 0) 
 | 
            { 
 | 
                invalidIndices.Add(i); 
 | 
            } 
 | 
        } 
 | 
         
 | 
        return invalidIndices; 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 移除无效脚本 
 | 
    /// </summary> 
 | 
    private static void RemoveInvalidScript(GameObject gameObject, int componentIndex) 
 | 
    { 
 | 
        SerializedObject serializedObject = new SerializedObject(gameObject); 
 | 
        SerializedProperty componentsProperty = serializedObject.FindProperty("m_Component"); 
 | 
         
 | 
        if (componentIndex >= 0 && componentIndex < componentsProperty.arraySize) 
 | 
        { 
 | 
            componentsProperty.DeleteArrayElementAtIndex(componentIndex); 
 | 
            serializedObject.ApplyModifiedProperties(); 
 | 
            Debug.Log($"已从游戏对象 '{gameObject.name}' 移除无效脚本"); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 递归扫描所有子对象中的无效脚本 
 | 
    /// </summary> 
 | 
    [MenuItem("GameObject/递归扫描所有无效脚本", false, 21)] 
 | 
    private static void ScanAllInvalidScriptsRecursively() 
 | 
    { 
 | 
        GameObject selectedObject = Selection.activeGameObject; 
 | 
        if (selectedObject == null) 
 | 
        { 
 | 
            EditorUtility.DisplayDialog("错误", "请先选择一个游戏对象", "确定"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        List<KeyValuePair<GameObject, int>> invalidScripts = new List<KeyValuePair<GameObject, int>>(); 
 | 
        ScanInvalidScriptsInChildren(selectedObject, invalidScripts); 
 | 
  
 | 
        if (invalidScripts.Count > 0) 
 | 
        { 
 | 
            // 找到了无效脚本 
 | 
            Debug.LogWarning($"在游戏对象 '{selectedObject.name}' 及其子对象中发现 {invalidScripts.Count} 个无效脚本"); 
 | 
             
 | 
            // 显示结果窗口 
 | 
            InvalidScriptResultWindow.ShowWindow(invalidScripts); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            // 未找到无效脚本,尝试更深层次的扫描 
 | 
            if (currentScanMode != ScanMode.Deep) 
 | 
            { 
 | 
                if (EditorUtility.DisplayDialog("未找到无效脚本",  
 | 
                    $"在游戏对象 '{selectedObject.name}' 及其子对象中未发现无效脚本。\n\n是否要尝试深度扫描?这可能需要更长时间。",  
 | 
                    "深度扫描", "取消")) 
 | 
                { 
 | 
                    // 临时切换到深度扫描模式 
 | 
                    ScanMode previousMode = currentScanMode; 
 | 
                    currentScanMode = ScanMode.Deep; 
 | 
                     
 | 
                    // 重新扫描 
 | 
                    invalidScripts.Clear(); 
 | 
                    ScanInvalidScriptsInChildren(selectedObject, invalidScripts); 
 | 
                     
 | 
                    // 恢复之前的扫描模式 
 | 
                    currentScanMode = previousMode; 
 | 
                     
 | 
                    if (invalidScripts.Count > 0) 
 | 
                    { 
 | 
                        // 找到了无效脚本 
 | 
                        Debug.LogWarning($"深度扫描:在游戏对象 '{selectedObject.name}' 及其子对象中发现 {invalidScripts.Count} 个无效脚本"); 
 | 
                         
 | 
                        // 显示结果窗口 
 | 
                        InvalidScriptResultWindow.ShowWindow(invalidScripts); 
 | 
                    } 
 | 
                    else 
 | 
                    { 
 | 
                        // 深度扫描也未找到无效脚本 
 | 
                        EditorUtility.DisplayDialog("深度扫描完成", $"在游戏对象 '{selectedObject.name}' 及其子对象中未发现无效脚本。", "确定"); 
 | 
                    } 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    // 用户取消深度扫描 
 | 
                    EditorUtility.DisplayDialog("扫描完成", $"在游戏对象 '{selectedObject.name}' 及其子对象中未发现无效脚本。", "确定"); 
 | 
                } 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                // 已经是深度扫描模式 
 | 
                EditorUtility.DisplayDialog("扫描完成", $"在游戏对象 '{selectedObject.name}' 及其子对象中未发现无效脚本。", "确定"); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 递归扫描子对象 
 | 
    /// </summary> 
 | 
    private static void ScanInvalidScriptsInChildren(GameObject gameObject, List<KeyValuePair<GameObject, int>> results) 
 | 
    { 
 | 
        // 使用改进的方法检测无效脚本 
 | 
        List<int> invalidIndices = FindInvalidScripts(gameObject); 
 | 
         
 | 
        // 添加到结果列表 
 | 
        foreach (int index in invalidIndices) 
 | 
        { 
 | 
            results.Add(new KeyValuePair<GameObject, int>(gameObject, index)); 
 | 
        } 
 | 
  
 | 
        // 递归检查所有子对象(包括隐藏的) 
 | 
        foreach (Transform child in gameObject.transform) 
 | 
        { 
 | 
            ScanInvalidScriptsInChildren(child.gameObject, results); 
 | 
        } 
 | 
    } 
 | 
     
 | 
    /// <summary> 
 | 
    /// 添加设置菜单项 
 | 
    /// </summary> 
 | 
    [MenuItem("GameObject/无效脚本扫描设置", false, 22)] 
 | 
    private static void ShowSettings() 
 | 
    { 
 | 
        // 创建设置窗口 
 | 
        InvalidScriptScannerSettings.ShowWindow(); 
 | 
    } 
 | 
} 
 | 
  
 | 
/// <summary> 
 | 
/// 无效脚本扫描设置窗口 
 | 
/// </summary> 
 | 
public class InvalidScriptScannerSettings : EditorWindow 
 | 
{ 
 | 
    private static string[] scanModeNames = { "基本扫描", "高级扫描", "深度扫描" }; 
 | 
     
 | 
    public static void ShowWindow() 
 | 
    { 
 | 
        InvalidScriptScannerSettings window = GetWindow<InvalidScriptScannerSettings>("无效脚本扫描设置"); 
 | 
        window.minSize = new Vector2(300, 150); 
 | 
        window.Show(); 
 | 
    } 
 | 
     
 | 
    private void OnGUI() 
 | 
    { 
 | 
        EditorGUILayout.LabelField("扫描设置", EditorStyles.boldLabel); 
 | 
        EditorGUILayout.Space(); 
 | 
         
 | 
        // 获取当前扫描模式 
 | 
        int currentMode = (int)typeof(InvalidScriptScanner).GetField("currentScanMode",  
 | 
            BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); 
 | 
         
 | 
        // 显示扫描模式选择 
 | 
        int newMode = EditorGUILayout.Popup("扫描模式", currentMode, scanModeNames); 
 | 
         
 | 
        // 如果模式发生变化,更新设置 
 | 
        if (newMode != currentMode) 
 | 
        { 
 | 
            typeof(InvalidScriptScanner).GetField("currentScanMode",  
 | 
                BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, newMode); 
 | 
        } 
 | 
         
 | 
        EditorGUILayout.Space(); 
 | 
        EditorGUILayout.HelpBox("扫描模式说明:\n" + 
 | 
            "基本扫描:只检查明显的无效脚本\n" + 
 | 
            "高级扫描:检查更多类型的无效脚本,包括隐藏对象\n" + 
 | 
            "深度扫描:进行最彻底的检查,但可能较慢", MessageType.Info); 
 | 
    } 
 | 
} 
 | 
  
 | 
/// <summary> 
 | 
/// 无效脚本结果窗口 
 | 
/// </summary> 
 | 
public class InvalidScriptResultWindow : EditorWindow 
 | 
{ 
 | 
    private List<KeyValuePair<GameObject, int>> invalidScripts; 
 | 
    private Vector2 scrollPosition; 
 | 
  
 | 
    public static void ShowWindow(List<KeyValuePair<GameObject, int>> scripts) 
 | 
    { 
 | 
        InvalidScriptResultWindow window = GetWindow<InvalidScriptResultWindow>("无效脚本扫描结果"); 
 | 
        window.invalidScripts = scripts; 
 | 
        window.minSize = new Vector2(400, 300); 
 | 
        window.Show(); 
 | 
    } 
 | 
  
 | 
    private void OnGUI() 
 | 
    { 
 | 
        if (invalidScripts == null || invalidScripts.Count == 0) 
 | 
        { 
 | 
            EditorGUILayout.LabelField("没有发现无效脚本"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        EditorGUILayout.LabelField($"发现 {invalidScripts.Count} 个无效脚本", EditorStyles.boldLabel); 
 | 
        EditorGUILayout.Space(); 
 | 
  
 | 
        if (GUILayout.Button("移除所有无效脚本")) 
 | 
        { 
 | 
            if (EditorUtility.DisplayDialog("确认", "确定要移除所有无效脚本吗?", "确定", "取消")) 
 | 
            { 
 | 
                RemoveAllInvalidScripts(); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        EditorGUILayout.Space(); 
 | 
        scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); 
 | 
  
 | 
        for (int i = 0; i < invalidScripts.Count; i++) 
 | 
        { 
 | 
            EditorGUILayout.BeginHorizontal(); 
 | 
             
 | 
            if (GUILayout.Button("选择", GUILayout.Width(60))) 
 | 
            { 
 | 
                Selection.activeGameObject = invalidScripts[i].Key; 
 | 
                EditorGUIUtility.PingObject(invalidScripts[i].Key); 
 | 
            } 
 | 
             
 | 
            EditorGUILayout.ObjectField(invalidScripts[i].Key, typeof(GameObject), true); 
 | 
             
 | 
            EditorGUILayout.LabelField($"组件索引: {invalidScripts[i].Value}", GUILayout.Width(100)); 
 | 
             
 | 
            if (GUILayout.Button("移除", GUILayout.Width(60))) 
 | 
            { 
 | 
                RemoveInvalidScript(invalidScripts[i].Key, invalidScripts[i].Value); 
 | 
                invalidScripts.RemoveAt(i); 
 | 
                i--; 
 | 
                GUIUtility.ExitGUI(); 
 | 
            } 
 | 
             
 | 
            EditorGUILayout.EndHorizontal(); 
 | 
        } 
 | 
  
 | 
        EditorGUILayout.EndScrollView(); 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 移除无效脚本 
 | 
    /// </summary> 
 | 
    private void RemoveInvalidScript(GameObject gameObject, int componentIndex) 
 | 
    { 
 | 
        SerializedObject serializedObject = new SerializedObject(gameObject); 
 | 
        SerializedProperty componentsProperty = serializedObject.FindProperty("m_Component"); 
 | 
         
 | 
        if (componentIndex >= 0 && componentIndex < componentsProperty.arraySize) 
 | 
        { 
 | 
            componentsProperty.DeleteArrayElementAtIndex(componentIndex); 
 | 
            serializedObject.ApplyModifiedProperties(); 
 | 
            Debug.Log($"已从游戏对象 '{gameObject.name}' 移除无效脚本"); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 移除所有无效脚本 
 | 
    /// </summary> 
 | 
    private void RemoveAllInvalidScripts() 
 | 
    { 
 | 
        // 创建一个副本,因为我们会在循环中修改原始列表 
 | 
        var scripts = new List<KeyValuePair<GameObject, int>>(invalidScripts); 
 | 
         
 | 
        // 按照组件索引从大到小排序,这样删除时不会影响其他组件的索引 
 | 
        scripts = scripts.OrderByDescending(pair => pair.Value) 
 | 
                         .GroupBy(pair => pair.Key) 
 | 
                         .SelectMany(group => group.OrderByDescending(pair => pair.Value)) 
 | 
                         .ToList(); 
 | 
         
 | 
        foreach (var pair in scripts) 
 | 
        { 
 | 
            RemoveInvalidScript(pair.Key, pair.Value); 
 | 
        } 
 | 
         
 | 
        invalidScripts.Clear(); 
 | 
        Repaint(); 
 | 
    } 
 | 
} 
 |