using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
///
/// Removes orphaned MonoBehaviour components whose script asset no longer exists
/// (the "The referenced script on this Behaviour is missing!" warnings seen in the
/// WebGPU build console). Operates on every GameObject in the currently open scene(s),
/// including inactive ones. Safe: only removes components Unity already reports as missing.
///
public static class RemoveMissingScripts
{
[MenuItem("Tools/Cleanup/Remove Missing Scripts In Open Scene(s)")]
public static void RemoveInOpenScenes()
{
int totalRemoved = 0;
int objectsAffected = 0;
var report = new StringBuilder();
for (int s = 0; s < SceneManager.sceneCount; s++)
{
Scene scene = SceneManager.GetSceneAt(s);
if (!scene.isLoaded) continue;
foreach (GameObject root in scene.GetRootGameObjects())
{
foreach (Transform t in root.GetComponentsInChildren(true))
{
GameObject go = t.gameObject;
int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(go);
if (count == 0) continue;
Undo.RegisterCompleteObjectUndo(go, "Remove Missing Scripts");
int removed = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go);
if (removed > 0)
{
totalRemoved += removed;
objectsAffected++;
report.AppendLine($" {removed} on '{GetPath(go)}'");
EditorSceneManager.MarkSceneDirty(scene);
}
}
}
}
if (totalRemoved == 0)
Debug.Log("[RemoveMissingScripts] No missing scripts found in the open scene(s).");
else
Debug.Log($"[RemoveMissingScripts] Removed {totalRemoved} missing script component(s) from {objectsAffected} object(s):\n{report}\nSave the scene (Ctrl+S) to persist.");
}
private static string GetPath(GameObject go)
{
string path = go.name;
Transform p = go.transform.parent;
while (p != null)
{
path = p.name + "/" + path;
p = p.parent;
}
return path;
}
}