#if UNITY_EDITOR
namespace Fury.Editor
{
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor;
public class MissingReferenceFinder : EditorWindow
{
private Vector2 scrollPos = Vector2.zero;
GUIStyle headStyle = new GUIStyle();
private int selectedButtonIndex = -1;
private Color selectedColor = Color.white;
public List<Result> results = new List<Result>();
[MenuItem("工具箱/一键移除丢失脚本")]
public static void ShowWindow()
{
MissingReferenceFinder window = GetWindow<MissingReferenceFinder>();
window.titleContent = new GUIContent("MissingReferenceFinder");
window.Show();
}
private void OnEnable()
{
headStyle.fontSize = 15;
headStyle.fontStyle = FontStyle.Bold;
headStyle.alignment = TextAnchor.MiddleCenter;
headStyle.normal.textColor = Color.white;
}
public void OnGUI()
{
EditorGUILayout.BeginVertical(GUILayout.Width(position.width), GUILayout.Height(position.height));
{
GUILayout.Space(10); // Add gap before the heading
DrawLabel("一键移除丢失脚本", headStyle);
GUILayout.Space(10); // Add gap after the heading
EditorGUILayout.BeginHorizontal();
{
if (GUILayout.Button("搜索资源文件夹", GetButtonStyle(0)))
{
selectedButtonIndex = 0;
SearchAssetFolder();
}
if (GUILayout.Button("搜索当前场景", GetButtonStyle(1)))
{
selectedButtonIndex = 1;
SearchCurrentScene();
}
if (GUILayout.Button("搜索选中的物体", GetButtonStyle(2)))
{
selectedButtonIndex = 2;
SerachSelectedAsset();
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(position.width - 5), GUILayout.Height(position.height - 105));
{
scrollPos = EditorGUILayout.BeginScrollView(scrollPos); // Adding scroll view for the Components List
{
foreach (var item in results)
{
EditorGUILayout.ObjectField(item.Obj, typeof(GameObject), true);
}
}
EditorGUILayout.EndScrollView();
}
EditorGUILayout.EndVertical();
if (GUI.Button(new Rect(position.width / 2 - 60, position.height - 35, 120, 30), "一键清除空引用"))
{
ClearNowNullCommponents();
}
}
EditorGUILayout.EndVertical();
}
private void ClearNowNullCommponents()
{
Debug.Log("当前拥有空脚本引用的物体个数:" + results.Count);
for (int x = 0; x < results.Count; x++)
{
GameObjectUtility.RemoveMonoBehavioursWithMissingScript(results[x].Obj);
}
Debug.Log("移除成功");
}
private GUIStyle GetButtonStyle(int buttonIndex)
{
if (buttonIndex == selectedButtonIndex)
{
// Create a GUIStyle for the selected button appearance
GUIStyle selectedButtonStyle = new GUIStyle(EditorStyles.toolbarButton);
// Adjust the visual properties to make the border more visible
selectedButtonStyle.normal.textColor = Color.white; // Change the text color
selectedButtonStyle.normal.background = MakeTexture(2, 2, new Color(0.49f, 0.25f, 0.03f, 1f)); // Add a background color
return selectedButtonStyle;
}
else
{
// Return the default button style
return EditorStyles.miniButton;
}
}
private Texture2D MakeTexture(int width, int height, Color color)
{
Color[] pixels = new Color[width * height];
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = color;
}
Texture2D texture = new Texture2D(width, height);
texture.SetPixels(pixels);
texture.Apply();
return texture;
}
private void DrawLabel(string text, GUIStyle style)
{
Rect rect = GUILayoutUtility.GetRect(GUIContent.none, style);
Color32 color = new Color32(125, 64, 8, 225);
EditorGUI.DrawRect(rect, color);
GUI.Label(rect, text, style);
}
private void SerachSelectedAsset()
{
results.Clear();
if (Selection.activeGameObject)
Traverse(Selection.activeGameObject.transform);
Debug.Log("> Total Results: " + results.Count);
}
public void SearchCurrentScene()
{
results.Clear();
GameObject[] gos = SceneManager.GetActiveScene().GetRootGameObjects();
foreach (GameObject go in gos) Traverse(go.transform);
Debug.Log("> Total Results: " + results.Count);
}
public void SearchAssetFolder()
{
results.Clear();
var allPrefabs = GetAllPrefabAddress();
int count = 0;
EditorUtility.DisplayProgressBar("Processing...", "Begin Job", 0);
foreach (string prefab in allPrefabs)
{
UnityEngine.Object o = AssetDatabase.LoadMainAssetAtPath(prefab);
if (o == null)
{
Debug.Log("prefab " + prefab + " null?");
continue;
}
GameObject go;
go = o as GameObject;
if (go != null)
{
EditorUtility.DisplayProgressBar("Processing...", go.name, ++count / (float)allPrefabs.Length);
Traverse(go.transform);
}
}
Debug.Log("> Total Results: " + results.Count);
EditorUtility.ClearProgressBar();
}
public string[] GetAllPrefabAddress()
{
string[] temp = AssetDatabase.GetAllAssetPaths();
List<string> result = new List<string>();
foreach (string s in temp)
{
if (s.Contains(".prefab")) result.Add(s);
}
return result.ToArray();
}
private void AppendComponentResult(string childPath, int index, GameObject obj)
{
results.Add(new Result()
{
address = "Missing Component " + index + " of " + childPath,
Obj = obj,
});
}
private void AppendTransformResult(string childPath, string name, GameObject obj)
{
results.Add(new Result()
{
address = "Missing Prefab for \"" + name + "\" of " + childPath,
Obj = obj,
});
}
private void Traverse(Transform transform, string path = "")
{
string thisPath = path + "/" + transform.name;
Component[] components = transform.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
if (components[i] == null)
{
AppendComponentResult(thisPath, i, transform.gameObject);
}
}
for (int c = 0; c < transform.childCount; c++)
{
Transform t = transform.GetChild(c);
PrefabAssetType pt = PrefabUtility.GetPrefabAssetType(t.gameObject);
if (pt == PrefabAssetType.MissingAsset)
{
AppendTransformResult(path + "/" + transform.name, t.name, transform.gameObject);
}
else
{
Traverse(t, thisPath);
}
}
}
}
[System.Serializable]
public class Result
{
public string address;
public GameObject Obj;
}
}
#endif