摄像机区域的架构改动
This commit is contained in:
230
Assets/_Game/Scripts/Editor/Tools/MissingScriptCleaner.cs
Normal file
230
Assets/_Game/Scripts/Editor/Tools/MissingScriptCleaner.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 扫描当前场景及 Project 中所有 Prefab,移除丢失(Missing)脚本引用。
|
||||
///
|
||||
/// 菜单:BaseGames/Tools/Missing Scripts/
|
||||
/// </summary>
|
||||
public static class MissingScriptCleaner
|
||||
{
|
||||
// ──────────────────────────────────────────────
|
||||
// 场景
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
[MenuItem("BaseGames/Tools/Missing Scripts/Clear In Scene")]
|
||||
public static void ClearMissingScriptsInScene()
|
||||
{
|
||||
int totalRemoved = 0;
|
||||
var affected = new List<GameObject>();
|
||||
|
||||
foreach (var go in GetAllSceneObjects())
|
||||
{
|
||||
int removed = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go);
|
||||
if (removed > 0)
|
||||
{
|
||||
affected.Add(go);
|
||||
totalRemoved += removed;
|
||||
EditorUtility.SetDirty(go);
|
||||
Debug.Log($"[MissingScriptCleaner] 场景已清理:{GetFullPath(go)}", go);
|
||||
}
|
||||
}
|
||||
|
||||
if (totalRemoved == 0)
|
||||
Debug.Log("[MissingScriptCleaner] 场景中未发现丢失脚本。");
|
||||
else
|
||||
Debug.Log($"[MissingScriptCleaner] 场景完成。共移除 {totalRemoved} 个丢失脚本,影响 {affected.Count} 个 GameObject。");
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Tools/Missing Scripts/Find In Scene")]
|
||||
public static void FindMissingScriptsInScene()
|
||||
{
|
||||
int totalFound = 0;
|
||||
|
||||
foreach (var go in GetAllSceneObjects())
|
||||
{
|
||||
foreach (var component in go.GetComponents<Component>())
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
Debug.LogWarning($"[MissingScriptCleaner] 场景丢失脚本:{GetFullPath(go)}", go);
|
||||
totalFound++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalFound == 0)
|
||||
Debug.Log("[MissingScriptCleaner] 场景中未发现丢失脚本。");
|
||||
else
|
||||
Debug.LogWarning($"[MissingScriptCleaner] 场景共发现 {totalFound} 个含丢失脚本的 GameObject。");
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// Prefab 资产
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
[MenuItem("BaseGames/Tools/Missing Scripts/Clear In All Prefabs")]
|
||||
public static void ClearMissingScriptsInPrefabs()
|
||||
{
|
||||
int totalRemoved = 0;
|
||||
int affectedPrefabs = 0;
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets("t:Prefab");
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
if (!path.StartsWith("Assets/")) continue; // 跳过 Packages 等只读路径
|
||||
|
||||
if (EditorUtility.DisplayCancelableProgressBar(
|
||||
"清理 Prefab 丢失脚本",
|
||||
path,
|
||||
(float)i / guids.Length))
|
||||
break;
|
||||
|
||||
int removed = CleanPrefabAtPath(path);
|
||||
if (removed > 0)
|
||||
{
|
||||
totalRemoved += removed;
|
||||
affectedPrefabs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
if (totalRemoved == 0)
|
||||
Debug.Log("[MissingScriptCleaner] 所有 Prefab 中未发现丢失脚本。");
|
||||
else
|
||||
Debug.Log($"[MissingScriptCleaner] Prefab 完成。共移除 {totalRemoved} 个丢失脚本,影响 {affectedPrefabs} 个 Prefab。");
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Tools/Missing Scripts/Find In All Prefabs")]
|
||||
public static void FindMissingScriptsInPrefabs()
|
||||
{
|
||||
int totalFound = 0;
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets("t:Prefab");
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
if (!path.StartsWith("Assets/")) continue; // 跳过 Packages 等只读路径
|
||||
|
||||
if (EditorUtility.DisplayCancelableProgressBar(
|
||||
"查找 Prefab 丢失脚本",
|
||||
path,
|
||||
(float)i / guids.Length))
|
||||
break;
|
||||
|
||||
var contentsRoot = PrefabUtility.LoadPrefabContents(path);
|
||||
if (contentsRoot == null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
var tempScene = contentsRoot.scene;
|
||||
foreach (var go in Resources.FindObjectsOfTypeAll<GameObject>())
|
||||
{
|
||||
if (go.scene != tempScene) continue;
|
||||
foreach (var component in go.GetComponents<Component>())
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
Debug.LogWarning($"[MissingScriptCleaner] Prefab 丢失脚本:{path} → {go.name}");
|
||||
totalFound++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrefabUtility.UnloadPrefabContents(contentsRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
if (totalFound == 0)
|
||||
Debug.Log("[MissingScriptCleaner] 所有 Prefab 中未发现丢失脚本。");
|
||||
else
|
||||
Debug.LogWarning($"[MissingScriptCleaner] Prefab 共发现 {totalFound} 个含丢失脚本的 GameObject。");
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// 内部辅助
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
static int CleanPrefabAtPath(string path)
|
||||
{
|
||||
// LoadPrefabContents 在临时预览场景中打开 Prefab,
|
||||
// 此时 Resources.FindObjectsOfTypeAll 可枚举到包括 HideInHierarchy 在内的全部对象。
|
||||
// 修改完毕后必须用 SaveAsPrefabAsset 写回,否则隐藏对象的改动不会持久化。
|
||||
var contentsRoot = PrefabUtility.LoadPrefabContents(path);
|
||||
if (contentsRoot == null) return 0;
|
||||
|
||||
int totalRemoved = 0;
|
||||
try
|
||||
{
|
||||
var tempScene = contentsRoot.scene;
|
||||
foreach (var go in Resources.FindObjectsOfTypeAll<GameObject>())
|
||||
{
|
||||
if (go.scene != tempScene) continue;
|
||||
int removed = GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go);
|
||||
if (removed > 0)
|
||||
{
|
||||
totalRemoved += removed;
|
||||
Debug.Log($"[MissingScriptCleaner] Prefab 已清理:{path} → {go.name}");
|
||||
}
|
||||
}
|
||||
|
||||
if (totalRemoved > 0)
|
||||
PrefabUtility.SaveAsPrefabAsset(contentsRoot, path);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrefabUtility.UnloadPrefabContents(contentsRoot);
|
||||
}
|
||||
|
||||
return totalRemoved;
|
||||
}
|
||||
|
||||
static GameObject[] GetAllSceneObjects()
|
||||
{
|
||||
// FindObjectsByType 不返回 HideFlags.HideInHierarchy 的对象,
|
||||
// 使用 Resources.FindObjectsOfTypeAll 获取全部对象,再过滤出已加载场景内的实例。
|
||||
var all = Resources.FindObjectsOfTypeAll<GameObject>();
|
||||
var result = new List<GameObject>();
|
||||
foreach (var go in all)
|
||||
{
|
||||
if (go.scene.IsValid() && go.scene.isLoaded)
|
||||
result.Add(go);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
static string GetFullPath(GameObject go)
|
||||
{
|
||||
var path = go.name;
|
||||
var parent = go.transform.parent;
|
||||
while (parent != null)
|
||||
{
|
||||
path = parent.name + "/" + path;
|
||||
parent = parent.parent;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user