166 lines
4.9 KiB
C#
166 lines
4.9 KiB
C#
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<string> errors = new List<string>();
|
|
|
|
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<MeshCollider>(true);
|
|
|
|
if (meshColliders != null)
|
|
{
|
|
List<MeshCollider> toRemove = new List<MeshCollider>();
|
|
|
|
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;
|
|
}
|
|
}
|