感谢吴蕴泽的部分代码Unity批处理修改prefab
感谢林新发的部分代码Unity3D编辑器:删掉MissingScirpt脚本
问题:使用其他地方的到的prefab,但是又丢弃了他们的脚本(他们的脚本不适合自己),实例化这个Prefab的时候,会在Editor下打印很多warning消息,这消息会影响加载效率,拖慢加载速度,甚至引起崩溃(在打包出来通过UnityWebRequest加载Bundle没问题,实例化的时候直接崩溃),有的同学会说,我手动删掉就是了呀,但是产品化的prefab往往数量相对庞大,结构相对复杂,一查可能有成百上千个丢失脚本的节点。
需求:将指定目录下所有prefab中丢失的脚本清理掉(递归清理,包括隐藏的节点,清理完成写回prefab)
建立测试环境:
第一步,建立空场景,添加根节点G1,添加两个子节点Child1 Child2 并分别附加一个新建的C#脚本 NewBehaviourScript.cs ,再将Child1隐藏,存储G1存为Prefab
第二步,删掉NewBehaviourScript.cs Apply Prefab:G1
好,这里已经建立起环境了,下面是Editor代码
[MenuItem("Tools/清理prefab中丢失的脚本")]
public static void RMLosedComponentInPrefab()
{
EditorUtility.DisplayProgressBar("Modify Prefab", "Please wait...", 0);
string[] ids = AssetDatabase.FindAssets("t:Prefab", new string[] { "Assets/data/testLoseScript" });
for (int i = 0; i < ids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(ids[i]);
GameObject prefab = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject;
GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
int delCount = 0;
RecersiceModifyGameObject(instance, ref delCount);
if (delCount > 0)
{
Debug.Log(instance.name + " remove losed:---- " + delCount);
// save
PrefabUtility.ReplacePrefab(instance, prefab, ReplacePrefabOptions.ConnectToPrefab);
}
UnityEngine.Object.DestroyImmediate(instance);
EditorUtility.DisplayProgressBar("Modify Prefab", "Please wait...", i / (float)ids.Length);
}
AssetDatabase.SaveAssets();
EditorUtility.ClearProgressBar();
}
private static void RecersiceModifyGameObject(GameObject obj, ref int delCount)
{
//find child
if (obj.transform.childCount > 0)
{
for (int i = 0; i < obj.transform.childCount; i++)
{
var _childObj = obj.transform.GetChild(i).gameObject;
// modify this GameObject
RecersiceModifyGameObject(_childObj, ref delCount);
}
}
// change instance
SerializedObject so = new SerializedObject(obj);
var soProperties = so.FindProperty("m_Component");
var components = obj.GetComponents<Component>();
int propertyIndex = 0;
int innerDelCount = 0;
foreach (var c in components)
{
if (c == null)
{
++delCount;
++innerDelCount;
soProperties.DeleteArrayElementAtIndex(propertyIndex);
}
++propertyIndex;
}
if (innerDelCount > 0)
so.ApplyModifiedProperties();
}
结果:
清理完成之后是这样的