摄像机区域的架构改动

This commit is contained in:
2026-05-15 14:47:24 +08:00
parent 1b37297585
commit f264329751
3591 changed files with 1687228 additions and 446503 deletions

View 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;
}
}
}