using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; namespace BaseGames.Editor { /// /// 编辑器 Edit Mode 辅助:打开任意场景时自动将 Persistent 场景 Additive 加入 Hierarchy。 /// /// 职责范围(仅限 Edit Mode): /// 让设计师在编辑房间场景时,Inspector 中可直接看到并配置 GameManager / SceneService /// 等 Persistent 场景内的组件,无需手动 Open Additive。 /// /// 运行时(Play Mode / 发行版 Build)的保证由 GameBootstrap(Runtime 程序集)负责, /// 本脚本与 Play Mode 状态无关,不监听 playModeStateChanged。 /// /// 菜单:BaseGames/Scene/Setup/Auto-Open Persistent Scene /// [InitializeOnLoad] public static class PersistentSceneAutoLoader { // ── 常量 ───────────────────────────────────────────────────────────── private const string MenuPath = "BaseGames/Scene/Setup/Auto-Open Persistent Scene"; private const string PrefKey = "BaseGames_EditAutoOpen_Persistent"; private const string PersistentSceneName = "Scene_Persistent"; // ── 构造(Editor 启动时执行)────────────────────────────────────────── static PersistentSceneAutoLoader() { EditorSceneManager.sceneOpened += OnSceneOpened; // 启动时补一次检查:Editor 已打开但 Persistent 不在 Hierarchy 的场景 EditorApplication.delayCall += EnsurePersistentInHierarchyEditMode; } // ── 菜单 ───────────────────────────────────────────────────────────── [MenuItem(MenuPath, validate = false, priority = 301)] private static void ToggleEnabled() { bool current = EditorPrefs.GetBool(PrefKey, true); EditorPrefs.SetBool(PrefKey, !current); } [MenuItem(MenuPath, validate = true)] private static bool ToggleEnabledValidate() { Menu.SetChecked(MenuPath, EditorPrefs.GetBool(PrefKey, true)); return true; } // ── 场景打开回调 ────────────────────────────────────────────────────── private static void OnSceneOpened(Scene scene, OpenSceneMode mode) { // 若是 Persistent 本身被打开,无需额外处理 if (IsPersistentScene(scene.name)) return; // Single 模式(替换当前场景)或 Additive 加入新场景时,确保 Persistent 也在 Hierarchy 中 // 使用 delayCall 避免在场景加载中途调用 OpenScene EditorApplication.delayCall += EnsurePersistentInHierarchyEditMode; } // ── 核心逻辑 ────────────────────────────────────────────────────────── private static void EnsurePersistentInHierarchyEditMode() { // 仅在 Edit Mode 执行(Play Mode 由 GameBootstrap 负责) if (Application.isPlaying) return; if (!EditorPrefs.GetBool(PrefKey, true)) return; // 若 Persistent 已在 Hierarchy,无需操作 for (int i = 0; i < SceneManager.sceneCount; i++) if (IsPersistentScene(SceneManager.GetSceneAt(i).name)) return; // 查找并 Additive 打开 Persistent 场景 string path = FindPersistentScenePath(); if (string.IsNullOrEmpty(path)) { Debug.LogWarning( $"[PersistentAutoLoader] 未找到 '{PersistentSceneName}' 场景。" + "请确认场景已添加到 Build Settings 或可在 Assets 中搜索到。"); return; } EditorSceneManager.OpenScene(path, OpenSceneMode.Additive); } // ── 工具函数 ────────────────────────────────────────────────────────── private static bool IsPersistentScene(string sceneName) => sceneName == PersistentSceneName || sceneName == "Persistent"; private static string FindPersistentScenePath() { // 优先从 Build Settings 查找(保证与 GameBootstrap 使用同一文件) foreach (var buildScene in EditorBuildSettings.scenes) { if (!buildScene.enabled) continue; string name = System.IO.Path.GetFileNameWithoutExtension(buildScene.path); if (IsPersistentScene(name)) return buildScene.path; } // 回退:在 AssetDatabase 中搜索 string[] guids = AssetDatabase.FindAssets($"t:Scene {PersistentSceneName}"); if (guids.Length > 0) return AssetDatabase.GUIDToAssetPath(guids[0]); guids = AssetDatabase.FindAssets("t:Scene Persistent"); return guids.Length > 0 ? AssetDatabase.GUIDToAssetPath(guids[0]) : null; } } }