工作中,有时会重构代码,有可能会重构继承MonoBehaviour的类,这时如果删除一些变量可能会影响到prefab的引用(因为有时这些引用名字每个类写的东不太一样,没办法通过代码搜索全部出来)。这时我特别想有个工具能通过我给的script然后返回有引用的prefab给我。
所以我决定自己写这个工具。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
public class ScriptReferenceSearch : EditorWindow
{
private static EditorWindow window;
private string m_ScriptName = "";
private string prefabNames;
[MenuItem("GameTools/资源查找/查找Script对应引用的prefab")]
public static void ShowWindow()
{
//Show existing window instance. If one doesn't exist, make one.
window = EditorWindow.GetWindow(typeof(ScriptReferenceSearch));
}
void OnGUI()
{
GUILayout.Label("查找prefab", EditorStyles.boldLabel);
m_ScriptName = EditorGUILayout.TextField("输入Script名:", m_ScriptName);
if (GUILayout.Button("查找"))
{
if (string.IsNullOrEmpty(m_ScriptName))
{
EditorUtility.DisplayDialog("请输入一个有效的Script名", "提示", "确定");
return;
}
System.Reflection.Assembly assembly = HierarchyUtils.GetAssembly();
Type type = assembly.GetType(m_ScriptName);
if (type == null)
{
EditorUtility.DisplayDialog("没找到该类:" + m_ScriptName, "提示", "确定");
return;
}
List<string> prefabNames = FindScriptInPrefab(type);
ShowPrefabNameEditor.ShowWindow(prefabNames);
}
}
private List<string> FindScriptInPrefab(Type scriptName)
{
List<string> prefabNames = new List<string>();
string[] prefabs = Directory.GetFiles("Assets/", "*.prefab", SearchOption.AllDirectories);
foreach (string prefab in prefabs)
{
GameObject go = AssetDatabase.LoadAssetAtPath(prefab, typeof(GameObject)) as GameObject;
if (go != null)
{
//Debug.LogError("scriptName:" + scriptName);
var component = go.GetComponentsInChildren(scriptName, true);
if (component != null && component.Length > 0)
{
foreach(var name in component)
{
prefabNames.Add(prefab + "_" + name);
}
}
}
}
return prefabNames;
}
}
public class ShowPrefabNameEditor : EditorWindow
{
private static List<string> PrefabNames = new List<string>();
public static void ShowWindow(List<string> prefabNames)
{
PrefabNames = prefabNames;
//创建窗口
Rect wr = new Rect(0, 0, 500, 500);
ShowPrefabNameEditor window = (ShowPrefabNameEditor)EditorWindow.GetWindowWithRect(typeof(ShowPrefabNameEditor), wr, true, "prefabName");
window.Show();
}
//输入文字的内容
private string text;
//绘制窗口时调用
void OnGUI()
{
StringBuilder strBuilder = new StringBuilder();
int count = PrefabNames.Count;
for (int i = 0; i < count; i++)
{
if (i == 0)
{
strBuilder.Append(PrefabNames[i]);
}
else
{
strBuilder.Append("\n");
strBuilder.Append(PrefabNames[i]);
}
}
//输入框控件
GUILayoutOption[] layouts = { GUILayout.MaxHeight(500) };
text = EditorGUILayout.TextField("查找结果:", strBuilder.ToString(), layouts);
}
}
当然我这里时全局查找,如果你想局部查找,只需修改对应的Directory.GetFiles的路径即可。
这里要说明一下HierarchyUtils.GetAssembly()。这个方法时在Assembly-CSharp.dll下的方法执行的。方式编写很简单
public static System.Reflection.Assembly GetAssembly()
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
return assembly;
}
就是通过反射获取所有的类。
为什么要在Assembly-CSharp.dll写而不直接在editor下直接写呢?
这是因为在editor下写的话他获取出来的只是Assembly-CSharp-Editor这个dll下的所有类。但我们实际上并不想获取这下面的类,因为这下面的都是editor的,并不会应用到运行时代码。所以必须写在Assembly-CSharp.dll下的方法才行。