140 lines
5.8 KiB
C#
140 lines
5.8 KiB
C#
using System.Collections.Generic;
|
||
using UnityEditor;
|
||
using UnityEditor.AddressableAssets;
|
||
using UnityEditor.AddressableAssets.Settings;
|
||
using UnityEditor.SceneManagement;
|
||
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
|
||
/// <summary>
|
||
/// 场景加载方式配置工具(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 空场景(唯一随主包的场景),只负责启动
|
||
/// </summary>
|
||
public static class BootSceneCreator
|
||
{
|
||
private const string BootScenePath = "Assets/MyGame/Scenes/BootScene.unity";
|
||
private const string UIScenePath = "Assets/MyGame/Scenes/UIScene.unity";
|
||
|
||
/// <summary>游戏场景(内部挂热更脚本,必须走 Addressables 加载)</summary>
|
||
private static readonly string[] GameSceneNames = { "XJMH", "FLZY", "HHWK", "YYSC" };
|
||
|
||
private static string GameScenePath(string name) => $"Assets/MyGame/Scenes/{name}.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. 把需要走 Addressables 的场景都标记好、并统一整理 Build Settings
|
||
SetupGameScenesToAddressablesInternal();
|
||
MarkSceneAddressable(UIScenePath, "UIScene");
|
||
|
||
// 4. 打开引导场景
|
||
EditorSceneManager.OpenScene(BootScenePath);
|
||
|
||
Debug.Log("[BootSceneCreator] 完成!请运行 HybridCLR > Generate > All 并重新构建。");
|
||
}
|
||
|
||
/// <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()
|
||
{
|
||
var scenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
|
||
|
||
// 先移除所有需要走 Addressables 的场景,避免重复
|
||
scenes.RemoveAll(s => s.path == BootScenePath);
|
||
scenes.RemoveAll(s => s.path == UIScenePath);
|
||
foreach (var name in GameSceneNames)
|
||
{
|
||
string path = GameScenePath(name);
|
||
scenes.RemoveAll(s => s.path == path);
|
||
}
|
||
|
||
// BootScene 插到最前面
|
||
scenes.Insert(0, new EditorBuildSettingsScene(BootScenePath, true));
|
||
|
||
EditorBuildSettings.scenes = scenes.ToArray();
|
||
|
||
Debug.Log("[BootSceneCreator] Build Settings 已更新:BootScene 为启动场景,UIScene/XJMH/FLZY/HHWK/YYSC 已移除(改走 Addressables)。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 把一个场景标记为 Addressable,address key 设为指定值(Launcher / 游戏内加载按这个 key 找)。
|
||
/// </summary>
|
||
private static void MarkSceneAddressable(string scenePath, string key)
|
||
{
|
||
var settings = AddressableAssetSettingsDefaultObject.Settings;
|
||
if (settings == null)
|
||
{
|
||
Debug.LogError("[BootSceneCreator] AddressableAssetSettings 不存在,请先初始化 Addressables。");
|
||
return;
|
||
}
|
||
|
||
string guid = AssetDatabase.AssetPathToGUID(scenePath);
|
||
if (string.IsNullOrEmpty(guid))
|
||
{
|
||
Debug.LogError($"[BootSceneCreator] 找不到场景: {scenePath}");
|
||
return;
|
||
}
|
||
|
||
// 用默认组(Default Local Group)。如果项目有专门的场景组,可手动改。
|
||
AddressableAssetGroup group = settings.DefaultGroup;
|
||
if (group == null)
|
||
{
|
||
Debug.LogError("[BootSceneCreator] Addressables 默认组不存在。");
|
||
return;
|
||
}
|
||
|
||
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, group);
|
||
entry.address = key;
|
||
|
||
EditorUtility.SetDirty(settings);
|
||
|
||
Debug.Log($"[BootSceneCreator] 场景已标记为 Addressable: {scenePath}(address='{key}',组='{group.Name}')。");
|
||
}
|
||
}
|