Files
5.24BuYu/Assets/Editor/BootSceneCreator.cs
T
2026-10-15 03:57:20 +08:00

109 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 创建纯 AOT 引导场景 BootScene 并配置 Build Settings / Addressables。
/// 引导场景保持全空(不挂任何组件),规避 HybridCLR "热更脚本不能挂在随主包场景上" 的限制。
/// 启动流程:BootScene(空)→ Launcher 加载热更 dll → 通过 Addressables 加载 UIScene。
/// </summary>
public static class BootSceneCreator
{
private const string BootScenePath = "Assets/MyGame/Scenes/BootScene.unity";
private const string UIScenePath = "Assets/MyGame/Scenes/UIScene.unity";
[MenuItem("Tools/Create BootScene")]
public static void CreateBootScene()
{
// 1. 新建空场景
// 引导场景必须保持“全空”:不挂任何热更 MonoBehaviour(否则构建时会被判为 missing script),
// 也不需要挂 AOT 单例——Launcher 是 static 类,靠 RuntimeInitializeOnLoadMethod 自动执行;
// BeijingTimeManager 是 MonoSingleton(Awake 里 DontDestroyOnLoad),它已经挂在 UIScene 上,
// 在这里再挂一份反而会产生两个实例(两份定时同步循环)。
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
// 2. 保存场景
bool saved = EditorSceneManager.SaveScene(scene, BootScenePath);
if (!saved)
{
Debug.LogError("[BootSceneCreator] 引导场景保存失败");
return;
}
Debug.Log($"[BootSceneCreator] 引导场景已创建: {BootScenePath}");
// 3. 更新 Build Settings:
// - BootScene 设为第一个(启动场景)
// - UIScene 从 Build Settings 移除(改为通过 Addressables 加载)
// - 其他场景保留
UpdateBuildSettings();
// 4. 把 UIScene 标记为 Addressable(key = "UIScene"),Launcher 会按这个 key 加载
MarkUISceneAddressable();
// 5. 打开引导场景
EditorSceneManager.OpenScene(BootScenePath);
Debug.Log("[BootSceneCreator] 完成!请运行 HybridCLR > Generate > All 并重新构建。");
}
private static void UpdateBuildSettings()
{
var scenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
// 移除已存在的 BootScene(防重复)
scenes.RemoveAll(s => s.path == BootScenePath);
// BootScene 插到最前面
scenes.Insert(0, new EditorBuildSettingsScene(BootScenePath, true));
// 移除 UIScene(现在由 Addressables 加载,不再随主包)
scenes.RemoveAll(s => s.path == UIScenePath);
EditorBuildSettings.scenes = scenes.ToArray();
Debug.Log("[BootSceneCreator] Build Settings 已更新:BootScene 为启动场景,UIScene 已移除(改走 Addressables)。");
}
/// <summary>
/// 把 UIScene 标记为 Addressable,address key 设为 "UIScene"。
/// Launcher 会按这个 key 通过 Addressables 加载主场景。
/// </summary>
private static void MarkUISceneAddressable()
{
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogError("[BootSceneCreator] AddressableAssetSettings 不存在,请先初始化 Addressables。");
return;
}
string uiSceneGuid = AssetDatabase.AssetPathToGUID(UIScenePath);
if (string.IsNullOrEmpty(uiSceneGuid))
{
Debug.LogError($"[BootSceneCreator] 找不到 UIScene: {UIScenePath}");
return;
}
// 用默认组(Default Local Group)。如果项目有专门的场景组,可手动改。
AddressableAssetGroup group = settings.DefaultGroup;
if (group == null)
{
Debug.LogError("[BootSceneCreator] Addressables 默认组不存在。");
return;
}
AddressableAssetEntry entry = settings.CreateOrMoveEntry(uiSceneGuid, group);
entry.address = "UIScene";
EditorUtility.SetDirty(settings);
AssetDatabase.SaveAssets();
Debug.Log($"[BootSceneCreator] UIScene 已标记为 Addressable,key='UIScene',组='{group.Name}'。");
}
}