add loadscene
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:59a38344245b9d816e9ee3749664edf1ced3bb23a176c93562f0e7ef78ac22aa
|
||||
size 311690
|
||||
oid sha256:118edff57ce13d46edc50acb1387bca1d79d66795958be304ef1e9d017cff634
|
||||
size 309966
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a5ca144887d8b4ad62b05ed4ee96ef2ff817460dd87d9a70a30ca6a1f750fe30
|
||||
size 5293
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7231194cdbf312f4ea3bc0583146e93f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -13,7 +13,10 @@ using UnityEngine.U2D;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>Runs after <see cref="GameContentBootstrap"/> (-2000) so bootstrap Awake creates the gate first.</summary>
|
||||
/// <summary>
|
||||
/// Scene game (Bootstrap): chờ gate chỉ khi <see cref="GameContentBootstrap"/> cùng scene.
|
||||
/// Nếu đã chạy scene GameContentBootstrap trước → <see cref="GameContentBootstrapSession.IsContentReady"/>.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-1990)]
|
||||
public class AddressableManager : MonoSingleton<AddressableManager>
|
||||
{
|
||||
@@ -84,6 +87,13 @@ namespace BrewMonster.Scripts
|
||||
/// Waits for <see cref="GameContentBootstrap"/> (version HTTP + optional URL rewrite) when that gate is active.
|
||||
/// </summary>
|
||||
async UniTaskVoid StartAddressablesInitAfterBootstrapGate()
|
||||
{
|
||||
if (GameContentBootstrapSession.IsContentReady || AddressablesInitService.IsInitialized)
|
||||
{
|
||||
Debug.Log(
|
||||
$"[Cuong] AddressableManager: Content bootstrap đã chạy ở scene trước — init Addressables (scene={SceneManager.GetActiveScene().name}).");
|
||||
}
|
||||
else
|
||||
{
|
||||
var gateState = GameContentBootstrap.GetGateDebugState();
|
||||
Debug.Log(
|
||||
@@ -95,10 +105,11 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[Cuong] AddressableManager: Bootstrap gate timeout ({_bootstrapGateWaitTimeoutSeconds:F0}s) — " +
|
||||
"InitializeAsync anyway. Check GameContentBootstrap lifecycle logs.");
|
||||
"InitializeAsync anyway. Nên dùng scene GameContentBootstrap riêng (index 0).");
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("[Cuong] AddressableManager: Bootstrap gate xong — đang InitializeAsync Addressables...");
|
||||
Debug.Log("[Cuong] AddressableManager: Đang InitializeAsync Addressables...");
|
||||
try
|
||||
{
|
||||
await AddressablesInitService.EnsureInitializedAsync();
|
||||
|
||||
@@ -52,8 +52,12 @@ namespace BrewMonster.Scripts
|
||||
|
||||
try
|
||||
{
|
||||
if (!GameContentBootstrapSession.IsContentReady)
|
||||
await GameContentBootstrap.WaitForPreAddressablesSetupIfAnyAsync();
|
||||
Debug.Log("[Cuong] AddressablesInitService: Bootstrap gate OK — InitializeAsync...");
|
||||
else
|
||||
Debug.Log("[Cuong] AddressablesInitService: Content scene đã sync — bỏ chờ gate.");
|
||||
|
||||
Debug.Log("[Cuong] AddressablesInitService: InitializeAsync...");
|
||||
|
||||
var handle = Addressables.InitializeAsync();
|
||||
await handle.ToUniTask();
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5cbe16c40166b34c9a3f9e967dfc694
|
||||
@@ -8,10 +8,8 @@ using UnityEngine.SceneManagement;
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Bootstrap: lấy contentVersion + (tuỳ chọn) assetsBaseUrl qua server hoặc hardcode, gắn URL rewrite trước khi Addressables init,
|
||||
/// rồi nếu lần đầu hoặc contentVersion khác đã lưu thì cập nhật catalog và tải toàn bộ entry gắn label.
|
||||
/// First run / version bump: resolve version + optional assetsBaseUrl (server or hardcoded), apply URL rewrite before Addressables init,
|
||||
/// then if first launch or stored version differs, update catalogs and download all entries under the configured label.
|
||||
/// Scene riêng (khuyến nghị index 0 trong Build Settings): version + URL rewrite → Addressables init → catalog/bulk.
|
||||
/// Khi xong, load scene game (<see cref="_nextSceneName"/>, thường <c>Bootstrap</c>) — scene đó không cần component này.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-2000)]
|
||||
public class GameContentBootstrap : MonoBehaviour
|
||||
@@ -87,6 +85,19 @@ namespace BrewMonster.Scripts
|
||||
[SerializeField]
|
||||
string _editorFakeContentVersion = "editor";
|
||||
|
||||
[Header("Scene flow (dedicated content scene)")]
|
||||
[Tooltip("Bật: sau khi sync content thành công, LoadScene Single sang scene game. Tắt: chỉ chạy sync (dùng khi gắn chung scene Bootstrap).")]
|
||||
[SerializeField]
|
||||
bool _loadNextSceneAfterSuccess = true;
|
||||
|
||||
[Tooltip("Tên scene trong Build Settings (vd Bootstrap). BootstrapSceneController trong scene đó sẽ load LoginScene.")]
|
||||
[SerializeField]
|
||||
string _nextSceneName = "Bootstrap";
|
||||
|
||||
[Tooltip("Khi sync thất bại, không load scene game (ở lại scene content để xử lý / retry).")]
|
||||
[SerializeField]
|
||||
bool _stayOnSceneWhenSyncFails = true;
|
||||
|
||||
public event Action<BootstrapResult> Finished;
|
||||
|
||||
/// <summary>Trạng thái gate tĩnh — dùng log chẩn đoán từ <see cref="AddressableManager"/>.</summary>
|
||||
@@ -110,6 +121,8 @@ namespace BrewMonster.Scripts
|
||||
|
||||
void Awake()
|
||||
{
|
||||
GameContentBootstrapSession.ResetForNewRun();
|
||||
s_bootstrapRunStarted = false;
|
||||
s_activeBootstrapInstanceId = GetInstanceID();
|
||||
_holdAddressablesInitConfigured = _holdAddressablesInitUntilVersionChecked;
|
||||
LogLifecycle("Awake");
|
||||
@@ -209,7 +222,32 @@ namespace BrewMonster.Scripts
|
||||
async UniTaskVoid RunAsync()
|
||||
{
|
||||
var result = await RunInternalAsync();
|
||||
if (result.Success)
|
||||
GameContentBootstrapSession.MarkContentReady();
|
||||
|
||||
Finished?.Invoke(result);
|
||||
await HandleSceneFlowAfterBootstrapAsync(result);
|
||||
}
|
||||
|
||||
async UniTask HandleSceneFlowAfterBootstrapAsync(BootstrapResult result)
|
||||
{
|
||||
if (!result.Success)
|
||||
{
|
||||
if (_stayOnSceneWhenSyncFails)
|
||||
Debug.LogError("[Cuong] GameContentBootstrap: Sync thất bại — ở lại scene content (không load game).");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_loadNextSceneAfterSuccess || string.IsNullOrWhiteSpace(_nextSceneName))
|
||||
{
|
||||
Debug.Log("[Cuong] GameContentBootstrap: Sync OK — không load scene tiếp (_loadNextSceneAfterSuccess tắt hoặc tên scene trống).");
|
||||
return;
|
||||
}
|
||||
|
||||
var next = _nextSceneName.Trim();
|
||||
await UniTask.Yield();
|
||||
Debug.Log($"[Cuong] GameContentBootstrap: Sync OK — LoadScene '{next}' (Single)...");
|
||||
SceneManager.LoadScene(next, LoadSceneMode.Single);
|
||||
}
|
||||
|
||||
public async UniTask<BootstrapResult> RunInternalAsync()
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Trạng thái phiên sau khi scene <c>GameContentBootstrap</c> hoàn tất (Addressables + catalog/bulk nếu cần).
|
||||
/// Scene game (<c>Bootstrap</c>) đọc flag này — không cần component <see cref="GameContentBootstrap"/> trong scene đó.
|
||||
/// </summary>
|
||||
public static class GameContentBootstrapSession
|
||||
{
|
||||
public static bool IsContentReady { get; private set; }
|
||||
|
||||
public static void MarkContentReady()
|
||||
{
|
||||
IsContentReady = true;
|
||||
}
|
||||
|
||||
public static void ResetForNewRun()
|
||||
{
|
||||
IsContentReady = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c7e6838c2213a9478bf29bb3f248949
|
||||
@@ -0,0 +1,95 @@
|
||||
#if UNITY_EDITOR
|
||||
using BrewMonster.Scripts;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace BrewMonster.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Tạo scene GameContentBootstrap và đưa lên đầu Build Settings (trước Bootstrap).
|
||||
/// </summary>
|
||||
public static class GameContentBootstrapSceneSetup
|
||||
{
|
||||
const string ContentScenePath = "Assets/PerfectWorld/Scene/GameContentBootstrap.unity";
|
||||
const string BootstrapScenePath = "Assets/PerfectWorld/Scene/Bootstrap.unity";
|
||||
|
||||
[MenuItem("Perfect World/Addressables/Setup Two-Scene Bootstrap")]
|
||||
public static void SetupTwoSceneBootstrap()
|
||||
{
|
||||
EnsureContentBootstrapScene();
|
||||
RemoveGameContentBootstrapFromBootstrapScene();
|
||||
ReorderBuildSettings();
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log(
|
||||
"[Cuong] Two-scene bootstrap: (0) GameContentBootstrap → (1) Bootstrap. " +
|
||||
"Gỡ GameContentBootstrap khỏi Bootstrap.unity; cấu hình _nextSceneName trên component trong scene Content.");
|
||||
}
|
||||
|
||||
static void EnsureContentBootstrapScene()
|
||||
{
|
||||
if (System.IO.File.Exists(ContentScenePath))
|
||||
return;
|
||||
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
|
||||
var root = new GameObject("GameContentBootstrap");
|
||||
var bootstrap = root.AddComponent<GameContentBootstrap>();
|
||||
|
||||
var so = new SerializedObject(bootstrap);
|
||||
so.FindProperty("_loadNextSceneAfterSuccess").boolValue = true;
|
||||
so.FindProperty("_nextSceneName").stringValue = "Bootstrap";
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
EditorSceneManager.SaveScene(scene, ContentScenePath);
|
||||
Debug.Log($"[Cuong] Created {ContentScenePath}");
|
||||
}
|
||||
|
||||
static void RemoveGameContentBootstrapFromBootstrapScene()
|
||||
{
|
||||
if (!System.IO.File.Exists(BootstrapScenePath))
|
||||
{
|
||||
Debug.LogWarning($"[Cuong] Missing {BootstrapScenePath}");
|
||||
return;
|
||||
}
|
||||
|
||||
var scene = EditorSceneManager.OpenScene(BootstrapScenePath, OpenSceneMode.Single);
|
||||
var targets = Object.FindObjectsByType<GameContentBootstrap>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
if (targets == null || targets.Length == 0)
|
||||
{
|
||||
Debug.Log("[Cuong] Bootstrap.unity: no GameContentBootstrap found (already clean).");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var t in targets)
|
||||
Object.DestroyImmediate(t.gameObject);
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
}
|
||||
|
||||
static void ReorderBuildSettings()
|
||||
{
|
||||
var scenes = new System.Collections.Generic.List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
|
||||
EditorBuildSettingsScene contentEntry = null;
|
||||
for (int i = scenes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (scenes[i].path == ContentScenePath)
|
||||
{
|
||||
contentEntry = scenes[i];
|
||||
scenes.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (contentEntry == null)
|
||||
contentEntry = new EditorBuildSettingsScene(ContentScenePath, true);
|
||||
|
||||
contentEntry.enabled = true;
|
||||
scenes.Insert(0, contentEntry);
|
||||
EditorBuildSettings.scenes = scenes.ToArray();
|
||||
Debug.Log("[Cuong] Build Settings: GameContentBootstrap is index 0.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a3ab2943a6c3ab44aee0633dc42a560
|
||||
Reference in New Issue
Block a user