using System.Reflection; using UnityEditor; using UnityEngine; using PathBerserker2d; namespace BaseGames.Editor { /// /// 快捷键:BaseGames → Tools → Bake All NavSurfaces(Ctrl+Shift+B) /// 烘焙当前场景中所有 PathBerserker2d NavSurface 的导航网格。 /// 等效于在每个 NavSurface Inspector 中逐一点击 "Bake"。 /// public static class NavSurfaceBakeShortcut { // NavSurface.StartBakeJob() 和 NavSurface.BakeJob 均为 internal,通过反射访问。 private static readonly MethodInfo s_startBakeJobMethod = typeof(NavSurface).GetMethod("StartBakeJob", BindingFlags.NonPublic | BindingFlags.Instance); private static readonly PropertyInfo s_bakeJobProp = typeof(NavSurface).GetProperty("BakeJob", BindingFlags.NonPublic | BindingFlags.Instance); [MenuItem("BaseGames/Tools/Bake All NavSurfaces %#b", priority = 100)] public static void BakeAll() { var surfaces = Object.FindObjectsByType(FindObjectsSortMode.None); if (surfaces.Length == 0) { Debug.Log("[NavSurfaceBake] 当前场景没有找到 NavSurface 组件。"); return; } int count = 0; foreach (var surface in surfaces) { if (surface == null) continue; s_startBakeJobMethod?.Invoke(surface, null); EditorApplication.update -= MakeWatcher(surface); EditorApplication.update += MakeWatcher(surface); count++; } Debug.Log($"[NavSurfaceBake] 开始烘焙 {count} 个 NavSurface……"); } [MenuItem("BaseGames/Tools/Bake All NavSurfaces %#b", validate = true)] private static bool BakeAllValidate() { // 仅在非 Play Mode 时可用(NavSurface.Bake 仅支持编辑器模式) return !Application.isPlaying; } // ── 每个 NavSurface 独立监听烘焙完成 ────────────────────────────── private static EditorApplication.CallbackFunction MakeWatcher(NavSurface surface) { EditorApplication.CallbackFunction watcher = null; watcher = () => { if (surface == null) { EditorApplication.update -= watcher; return; } var bakeJob = s_bakeJobProp?.GetValue(surface); if (bakeJob == null) { EditorApplication.update -= watcher; return; } bool isFinished = (bool)bakeJob.GetType() .GetProperty("IsFinished")!.GetValue(bakeJob); if (isFinished) { EditorApplication.update -= watcher; EditorUtility.SetDirty(surface); float totalTime = (float)bakeJob.GetType() .GetProperty("TotalBakeTime")!.GetValue(bakeJob); Debug.Log($"[NavSurfaceBake] ✓ {surface.name} 烘焙完成({totalTime} ms)"); } }; return watcher; } } }