149 lines
4.2 KiB
C#
149 lines
4.2 KiB
C#
using System;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text.RegularExpressions;
|
||
|
||
public class FindMissingPrefabs : EditorWindow
|
||
{
|
||
[MenuItem("Tools/Find Missing Prefabs")]
|
||
static void Init()
|
||
{
|
||
GetWindow<FindMissingPrefabs>("Find Missing Prefabs").Show();
|
||
}
|
||
|
||
private List<GameObject> missingPrefabs = new List<GameObject>();
|
||
|
||
void OnGUI()
|
||
{
|
||
if (GUILayout.Button("Find Missing Prefabs in Scene"))
|
||
{
|
||
FindMissing();
|
||
}
|
||
|
||
if (missingPrefabs.Count > 0)
|
||
{
|
||
GUILayout.Label("Missing Prefabs Found:", EditorStyles.boldLabel);
|
||
foreach (var obj in missingPrefabs.Take(32))
|
||
{
|
||
if (GUILayout.Button(obj.name))
|
||
{
|
||
Selection.activeGameObject = obj;
|
||
|
||
AutoFix(obj);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
GUILayout.Label("No missing prefabs found.");
|
||
}
|
||
}
|
||
|
||
void FindMissing()
|
||
{
|
||
missingPrefabs.Clear();
|
||
GameObject[] allObjects = GameObject.FindObjectsOfType<GameObject>();
|
||
|
||
foreach (GameObject obj in allObjects)
|
||
{
|
||
PrefabAssetType prefabType = PrefabUtility.GetPrefabAssetType(obj);
|
||
if (prefabType == PrefabAssetType.MissingAsset)
|
||
{
|
||
if (PrefabUtility.IsAnyPrefabInstanceRoot(obj) is false)continue;
|
||
AutoFix(obj);
|
||
missingPrefabs.Add(obj);
|
||
}
|
||
}
|
||
}
|
||
|
||
private bool AutoFix(GameObject obj)
|
||
{
|
||
// 解析 name(括号前的部分)
|
||
Match nameMatch = Regex.Match(obj.name, @"^(.+?)\s*\(");
|
||
|
||
var name = nameMatch.Success ? nameMatch.Groups[1].Value : "N/A";
|
||
if (nameMatch.Success is false)
|
||
{
|
||
Debug.LogWarning("未能解析到Name");
|
||
return false;
|
||
}
|
||
// 解析 guid
|
||
Match guidMatch = Regex.Match(obj.name, @"guid:\s*([a-f0-9]{32})");
|
||
|
||
if (guidMatch.Success is false)
|
||
{
|
||
Debug.LogWarning("未能解析到GUID");
|
||
return false;
|
||
}
|
||
var guid = guidMatch.Success ? guidMatch.Groups[1].Value : "N/A";
|
||
|
||
var searchStr =name+ @" t:prefab";
|
||
|
||
var searchPrefabs = AssetDatabase.FindAssets(searchStr);
|
||
|
||
Debug.Log($"找到:{name}有关的{searchStr}结果:\n"+string.Join("\n",searchPrefabs));
|
||
|
||
var errorGuid = string.Empty;
|
||
|
||
switch (searchPrefabs.Length)
|
||
{
|
||
case > 1:
|
||
{
|
||
try
|
||
{
|
||
foreach (var searchId in searchPrefabs)
|
||
{
|
||
var prefabName = AssetDatabase.GUIDToAssetPath(searchId);
|
||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabName);
|
||
if (prefab.name == name)
|
||
{
|
||
errorGuid = searchId;
|
||
throw new OperationCanceledException();
|
||
}
|
||
}
|
||
|
||
Debug.LogWarning($"找到的结果有:{searchPrefabs.Length},无法自动修复");
|
||
return false;
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
}
|
||
}
|
||
break;
|
||
case 1:
|
||
{
|
||
errorGuid = searchPrefabs[0];
|
||
}
|
||
|
||
break;
|
||
case 0:
|
||
{
|
||
Debug.Log("未找到");
|
||
}
|
||
break;
|
||
}
|
||
|
||
|
||
var path = AssetDatabase.GUIDToAssetPath(errorGuid);
|
||
var metaPath = path + ".meta";
|
||
metaPath = Path.Combine(Environment.CurrentDirectory, metaPath);
|
||
if (File.Exists(metaPath) is false)
|
||
{
|
||
Debug.Log($"Meta路径未找到:{{metaPath}}");
|
||
return false;
|
||
}
|
||
|
||
var str = File.ReadAllText(metaPath);
|
||
|
||
str = str.Replace(searchPrefabs[0], guid);
|
||
|
||
File.WriteAllText(metaPath, str);
|
||
|
||
Debug.Log($"{name}已修复");
|
||
|
||
return true;
|
||
}
|
||
} |