using UnityEngine; using UnityEditor; using System.Collections.Generic; public class RemoveInvalidMeshFromFolder { private const float MinBoundsSize = 0.2f; [MenuItem("Tools/Cleanup/Remove Invalid Meshes (Select Folder)")] static void RemoveInvalidMeshesFromFolder() { string absFolder = EditorUtility.OpenFolderPanel( "Select folder to clean prefabs (remove invalid MeshColliders)", Application.dataPath, "" ); if (string.IsNullOrEmpty(absFolder)) return; if (!absFolder.StartsWith(Application.dataPath)) { EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside your project's Assets folder.", "OK"); return; } string relFolder = "Assets" + absFolder.Substring(Application.dataPath.Length); string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab", new[] { relFolder }); if (prefabGuids == null || prefabGuids.Length == 0) { EditorUtility.DisplayDialog("No Prefabs Found", $"No prefabs found in the selected folder:\n{relFolder}", "OK"); return; } int scanned = 0; int modified = 0; List errors = new List(); try { AssetDatabase.StartAssetEditing(); foreach (string guid in prefabGuids) { if (string.IsNullOrEmpty(guid)) continue; string path = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(path)) continue; scanned++; GameObject instance = null; try { instance = PrefabUtility.LoadPrefabContents(path); } catch (System.Exception ex) { errors.Add($"{path}: Failed to load - {ex.Message}"); continue; } if (instance == null) { errors.Add($"{path}: LoadPrefabContents returned null"); continue; } bool changed = false; MeshCollider[] meshColliders = instance.GetComponentsInChildren(true); if (meshColliders != null) { List toRemove = new List(); foreach (MeshCollider mc in meshColliders) { if (mc == null) continue; if (ShouldRemoveMeshCollider(mc, out string reason)) { toRemove.Add(mc); } } foreach (MeshCollider mc in toRemove) { if (mc != null) { Object.DestroyImmediate(mc); changed = true; } } } if (changed) { try { PrefabUtility.SaveAsPrefabAsset(instance, path); modified++; } catch (System.Exception ex) { errors.Add($"{path}: Failed to save - {ex.Message}"); } } PrefabUtility.UnloadPrefabContents(instance); } } finally { AssetDatabase.StopAssetEditing(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } string message = $"Scanned: {scanned}\nModified: {modified}"; if (errors.Count > 0) { message += $"\n\nErrors ({errors.Count}):\n" + string.Join("\n", errors.GetRange(0, Mathf.Min(errors.Count, 5))); if (errors.Count > 5) message += $"\n... and {errors.Count - 5} more"; } EditorUtility.DisplayDialog("Remove Invalid Meshes - Finished", message, "OK"); } static bool ShouldRemoveMeshCollider(MeshCollider mc, out string reason) { reason = null; if (mc == null) { reason = "MeshCollider is null"; return true; } Mesh mesh = mc.sharedMesh; if (mesh == null) { reason = "Mesh is null"; return true; } Vector3 size = mesh.bounds.size; if (size.x < MinBoundsSize || size.y < MinBoundsSize || size.z < MinBoundsSize) { reason = $"Mesh bounds too small (x:{size.x:F3}, y:{size.y:F3}, z:{size.z:F3})"; return true; } return false; } }