using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; namespace BrewMonster.Scripts.Utils.Editor { public static class ClearMissingScript { [MenuItem("Tools/Brew Monster/Clear Missing Script/Active Scene")] public static void ClearMissingScriptsInActiveScene() { var scene = SceneManager.GetActiveScene(); if (!scene.IsValid()) { EditorUtility.DisplayDialog("Clear Missing Script", "No valid active scene.", "OK"); return; } int removedCount = 0; var roots = scene.GetRootGameObjects(); foreach (var root in roots) { Undo.RegisterFullObjectHierarchyUndo(root, "Clear Missing Scripts"); removedCount += RemoveMissingScriptsRecursive(root); } if (removedCount > 0) { EditorSceneManager.MarkSceneDirty(scene); } EditorUtility.DisplayDialog("Clear Missing Script", $"Removed {removedCount} missing script(s) from active scene.", "OK"); } [MenuItem("Tools/Brew Monster/Clear Missing Script/Prefabs in Selected Folder", true)] public static bool ValidateClearMissingScriptsInSelectedFolder() { Object selectedObject = Selection.activeObject; if (selectedObject == null) return false; string folderPath = AssetDatabase.GetAssetPath(selectedObject); return AssetDatabase.IsValidFolder(folderPath); } [MenuItem("Tools/Brew Monster/Clear Missing Script/Prefabs in Selected Folder")] public static void ClearMissingScriptsInSelectedFolder() { Object selectedObject = Selection.activeObject; if (selectedObject == null) { EditorUtility.DisplayDialog("Clear Missing Script", "Please select a folder in the Project window first.", "OK"); return; } string folderPath = AssetDatabase.GetAssetPath(selectedObject); if (!AssetDatabase.IsValidFolder(folderPath)) { EditorUtility.DisplayDialog("Clear Missing Script", "Selected object is not a valid folder. Please select a folder in the Project window.", "OK"); return; } if (!EditorUtility.DisplayDialog("Clear Missing Script in Folder", $"This will process all prefabs in:\n{folderPath}\n\nContinue?", "Yes", "Cancel")) { return; } ProcessPrefabsInFolder(folderPath); } [MenuItem("Tools/Brew Monster/Clear Missing Script/All Prefabs")] public static void ClearMissingScriptsInPrefabs() { if (!EditorUtility.DisplayDialog("Clear Missing Script in Prefabs", "This will process all prefabs in the project. This may take a while. Continue?", "Yes", "Cancel")) { return; } ProcessPrefabsInFolder("Assets"); } private static void ProcessPrefabsInFolder(string folderPath) { string[] prefabGUIDs = AssetDatabase.FindAssets("t:Prefab", new[] { folderPath }); int totalPrefabs = prefabGUIDs.Length; if (totalPrefabs == 0) { EditorUtility.DisplayDialog("Clear Missing Script", $"No prefabs found in folder:\n{folderPath}", "OK"); return; } int processedCount = 0; int totalRemovedCount = 0; int prefabsWithRemovals = 0; EditorUtility.DisplayProgressBar("Clear Missing Scripts", "Processing prefabs...", 0f); try { foreach (string guid in prefabGUIDs) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); processedCount++; EditorUtility.DisplayProgressBar("Clear Missing Scripts", $"Processing: {assetPath} ({processedCount}/{totalPrefabs})", (float)processedCount / totalPrefabs); GameObject prefabRoot = PrefabUtility.LoadPrefabContents(assetPath); if (prefabRoot != null) { int removedCount = RemoveMissingScriptsRecursive(prefabRoot); if (removedCount > 0) { PrefabUtility.SaveAsPrefabAsset(prefabRoot, assetPath); totalRemovedCount += removedCount; prefabsWithRemovals++; Debug.Log($"[ClearMissingScript] Removed {removedCount} missing script(s) from prefab: {assetPath}"); } PrefabUtility.UnloadPrefabContents(prefabRoot); } } AssetDatabase.SaveAssets(); } finally { EditorUtility.ClearProgressBar(); } EditorUtility.DisplayDialog("Clear Missing Script", $"Processed {processedCount} prefab(s) in folder:\n{folderPath}\n\nRemoved {totalRemovedCount} missing script(s) from {prefabsWithRemovals} prefab(s).", "OK"); } [MenuItem("Tools/Brew Monster/Clear Missing Script/Scene and Prefabs")] public static void ClearMissingScriptsInSceneAndPrefabs() { if (!EditorUtility.DisplayDialog("Clear Missing Script", "This will process the active scene and all prefabs in the project. This may take a while. Continue?", "Yes", "Cancel")) { return; } int sceneRemovedCount = 0; var scene = SceneManager.GetActiveScene(); if (scene.IsValid()) { var roots = scene.GetRootGameObjects(); foreach (var root in roots) { Undo.RegisterFullObjectHierarchyUndo(root, "Clear Missing Scripts"); sceneRemovedCount += RemoveMissingScriptsRecursive(root); } if (sceneRemovedCount > 0) { EditorSceneManager.MarkSceneDirty(scene); } } string[] prefabGUIDs = AssetDatabase.FindAssets("t:Prefab"); int totalPrefabs = prefabGUIDs.Length; int processedCount = 0; int prefabRemovedCount = 0; int prefabsWithRemovals = 0; EditorUtility.DisplayProgressBar("Clear Missing Scripts", "Processing prefabs...", 0f); try { foreach (string guid in prefabGUIDs) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); processedCount++; EditorUtility.DisplayProgressBar("Clear Missing Scripts", $"Processing: {assetPath} ({processedCount}/{totalPrefabs})", (float)processedCount / totalPrefabs); GameObject prefabRoot = PrefabUtility.LoadPrefabContents(assetPath); if (prefabRoot != null) { int removedCount = RemoveMissingScriptsRecursive(prefabRoot); if (removedCount > 0) { PrefabUtility.SaveAsPrefabAsset(prefabRoot, assetPath); prefabRemovedCount += removedCount; prefabsWithRemovals++; } PrefabUtility.UnloadPrefabContents(prefabRoot); } } AssetDatabase.SaveAssets(); } finally { EditorUtility.ClearProgressBar(); } int totalRemoved = sceneRemovedCount + prefabRemovedCount; EditorUtility.DisplayDialog("Clear Missing Script", $"Scene: Removed {sceneRemovedCount} missing script(s).\n" + $"Prefabs: Processed {processedCount} prefab(s), removed {prefabRemovedCount} missing script(s) from {prefabsWithRemovals} prefab(s).\n" + $"Total: {totalRemoved} missing script(s) removed.", "OK"); } private static int RemoveMissingScriptsRecursive(GameObject gameObject) { int removed = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(gameObject); for (int i = 0; i < gameObject.transform.childCount; i++) { removed += RemoveMissingScriptsRecursive(gameObject.transform.GetChild(i).gameObject); } return removed; } } }