This commit is contained in:
2026-10-15 03:57:20 +08:00
parent 8498afd5cf
commit 1932b8569b
70 changed files with 916 additions and 352 deletions
+108
View File
@@ -0,0 +1,108 @@
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}'。");
}
}