2026-10-15 03:57:20 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEditor.AddressableAssets;
|
|
|
|
|
|
using UnityEditor.AddressableAssets.Settings;
|
|
|
|
|
|
using UnityEditor.SceneManagement;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-10-17 03:01:15 +08:00
|
|
|
|
/// 场景加载方式配置工具(HybridCLR 配套):
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 规则:**凡是挂了热更脚本(Game.Hotfix)的场景,都不能随主包(Build Settings)加载**,
|
|
|
|
|
|
/// 必须通过 AssetBundle/Addressables 加载,否则运行时会变成 missing script
|
|
|
|
|
|
/// (典型现象:场景里的 MonoBehaviour 不工作,比如背景不动、UI 不响应)。
|
|
|
|
|
|
/// - UIScene:挂了 GameManager/TiShi/LoadingPanel/HuoDe 等 → 走 Addressables
|
|
|
|
|
|
/// - XJMH/FLZY/HHWK/YYSC:挂了 BGManager/BgFit 等 → 走 Addressables
|
|
|
|
|
|
/// - BootScene:纯 AOT 空场景(唯一随主包的场景),只负责启动
|
2026-10-15 03:57:20 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static class BootSceneCreator
|
|
|
|
|
|
{
|
|
|
|
|
|
private const string BootScenePath = "Assets/MyGame/Scenes/BootScene.unity";
|
|
|
|
|
|
private const string UIScenePath = "Assets/MyGame/Scenes/UIScene.unity";
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
/// <summary>游戏场景(内部挂热更脚本,必须走 Addressables 加载)</summary>
|
|
|
|
|
|
private static readonly string[] GameSceneNames = { "XJMH", "FLZY", "HHWK", "YYSC" };
|
|
|
|
|
|
|
|
|
|
|
|
private static string GameScenePath(string name) => $"Assets/MyGame/Scenes/{name}.unity";
|
|
|
|
|
|
|
2026-10-15 03:57:20 +08:00
|
|
|
|
[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}");
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
// 3. 把需要走 Addressables 的场景都标记好、并统一整理 Build Settings
|
|
|
|
|
|
SetupGameScenesToAddressablesInternal();
|
|
|
|
|
|
MarkSceneAddressable(UIScenePath, "UIScene");
|
2026-10-15 03:57:20 +08:00
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
// 4. 打开引导场景
|
2026-10-15 03:57:20 +08:00
|
|
|
|
EditorSceneManager.OpenScene(BootScenePath);
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log("[BootSceneCreator] 完成!请运行 HybridCLR > Generate > All 并重新构建。");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 把游戏场景(XJMH/FLZY/HHWK/YYSC)标记为 Addressable(address = 场景名),
|
|
|
|
|
|
/// 并把它们从 Build Settings 移除(改由 Addressables 加载)。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[MenuItem("Tools/Setup Game Scenes To Addressables")]
|
|
|
|
|
|
public static void SetupGameScenesToAddressables()
|
|
|
|
|
|
{
|
|
|
|
|
|
SetupGameScenesToAddressablesInternal();
|
|
|
|
|
|
Debug.Log("[BootSceneCreator] 游戏场景已标记为 Addressable(address = 场景名)并从 Build Settings 移除。请重新构建。");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void SetupGameScenesToAddressablesInternal()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var name in GameSceneNames)
|
|
|
|
|
|
MarkSceneAddressable(GameScenePath(name), name);
|
|
|
|
|
|
|
|
|
|
|
|
ApplyBuildSettings();
|
|
|
|
|
|
AssetDatabase.SaveAssets();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 统一整理 Build Settings:
|
|
|
|
|
|
/// - BootScene 放第一位(启动场景)
|
|
|
|
|
|
/// - UIScene 与 4 个游戏场景全部移除(它们都改走 Addressables 加载)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static void ApplyBuildSettings()
|
2026-10-15 03:57:20 +08:00
|
|
|
|
{
|
|
|
|
|
|
var scenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
// 先移除所有需要走 Addressables 的场景,避免重复
|
2026-10-15 03:57:20 +08:00
|
|
|
|
scenes.RemoveAll(s => s.path == BootScenePath);
|
2026-10-17 03:01:15 +08:00
|
|
|
|
scenes.RemoveAll(s => s.path == UIScenePath);
|
|
|
|
|
|
foreach (var name in GameSceneNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
string path = GameScenePath(name);
|
|
|
|
|
|
scenes.RemoveAll(s => s.path == path);
|
|
|
|
|
|
}
|
2026-10-15 03:57:20 +08:00
|
|
|
|
|
|
|
|
|
|
// BootScene 插到最前面
|
|
|
|
|
|
scenes.Insert(0, new EditorBuildSettingsScene(BootScenePath, true));
|
|
|
|
|
|
|
|
|
|
|
|
EditorBuildSettings.scenes = scenes.ToArray();
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
Debug.Log("[BootSceneCreator] Build Settings 已更新:BootScene 为启动场景,UIScene/XJMH/FLZY/HHWK/YYSC 已移除(改走 Addressables)。");
|
2026-10-15 03:57:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-10-17 03:01:15 +08:00
|
|
|
|
/// 把一个场景标记为 Addressable,address key 设为指定值(Launcher / 游戏内加载按这个 key 找)。
|
2026-10-15 03:57:20 +08:00
|
|
|
|
/// </summary>
|
2026-10-17 03:01:15 +08:00
|
|
|
|
private static void MarkSceneAddressable(string scenePath, string key)
|
2026-10-15 03:57:20 +08:00
|
|
|
|
{
|
|
|
|
|
|
var settings = AddressableAssetSettingsDefaultObject.Settings;
|
|
|
|
|
|
if (settings == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("[BootSceneCreator] AddressableAssetSettings 不存在,请先初始化 Addressables。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
string guid = AssetDatabase.AssetPathToGUID(scenePath);
|
|
|
|
|
|
if (string.IsNullOrEmpty(guid))
|
2026-10-15 03:57:20 +08:00
|
|
|
|
{
|
2026-10-17 03:01:15 +08:00
|
|
|
|
Debug.LogError($"[BootSceneCreator] 找不到场景: {scenePath}");
|
2026-10-15 03:57:20 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 用默认组(Default Local Group)。如果项目有专门的场景组,可手动改。
|
|
|
|
|
|
AddressableAssetGroup group = settings.DefaultGroup;
|
|
|
|
|
|
if (group == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("[BootSceneCreator] Addressables 默认组不存在。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, group);
|
|
|
|
|
|
entry.address = key;
|
2026-10-15 03:57:20 +08:00
|
|
|
|
|
|
|
|
|
|
EditorUtility.SetDirty(settings);
|
|
|
|
|
|
|
2026-10-17 03:01:15 +08:00
|
|
|
|
Debug.Log($"[BootSceneCreator] 场景已标记为 Addressable: {scenePath}(address='{key}',组='{group.Name}')。");
|
2026-10-15 03:57:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|