fix download addressable remote in mobile
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.U2D;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>Runs after <see cref="GameContentBootstrap"/> (-2000) so bootstrap Awake creates the gate first.</summary>
|
||||
[DefaultExecutionOrder(-1990)]
|
||||
public class AddressableManager : MonoSingleton<AddressableManager>
|
||||
{
|
||||
private bool _isInitialized = false;
|
||||
@@ -31,6 +35,14 @@ namespace BrewMonster.Scripts
|
||||
private Dictionary<string, float> _releaseAssetTimestamps = new();
|
||||
[SerializeField]private float _releaseAssetTimeout = 10f;
|
||||
|
||||
[Header("Bootstrap gate")]
|
||||
[Tooltip("Max seconds to wait for GameContentBootstrap before initializing Addressables anyway.")]
|
||||
[SerializeField]
|
||||
float _bootstrapGateWaitTimeoutSeconds = 50f;
|
||||
|
||||
[SerializeField]
|
||||
bool _verboseBootstrapWaitDebug = true;
|
||||
|
||||
public event Action OnDispose;
|
||||
|
||||
/// <summary>Get the count of currently loaded assets.</summary>
|
||||
@@ -48,6 +60,18 @@ namespace BrewMonster.Scripts
|
||||
return _initializationTcs.Task;
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
if (_verboseBootstrapWaitDebug)
|
||||
{
|
||||
Debug.Log(
|
||||
$"[Cuong] AddressableManager: Awake | id={GetInstanceID()} scene={SceneManager.GetActiveScene().name} " +
|
||||
$"frame={Time.frameCount} bootstrapGate={GameContentBootstrap.GetGateDebugState()}");
|
||||
}
|
||||
|
||||
base.Awake();
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -61,12 +85,38 @@ namespace BrewMonster.Scripts
|
||||
/// </summary>
|
||||
async UniTaskVoid StartAddressablesInitAfterBootstrapGate()
|
||||
{
|
||||
Debug.Log("[Cuong] AddressableManager: Đang chờ GameContentBootstrap (version / URL rewrite)...");
|
||||
await GameContentBootstrap.WaitForPreAddressablesSetupIfAnyAsync();
|
||||
var gateState = GameContentBootstrap.GetGateDebugState();
|
||||
Debug.Log(
|
||||
$"[Cuong] AddressableManager: Đang chờ GameContentBootstrap (version / URL rewrite)... | " +
|
||||
$"id={GetInstanceID()} scene={SceneManager.GetActiveScene().name} gate={gateState}");
|
||||
|
||||
var waited = await WaitForBootstrapGateWithTimeoutAsync();
|
||||
if (!waited)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[Cuong] AddressableManager: Bootstrap gate timeout ({_bootstrapGateWaitTimeoutSeconds:F0}s) — " +
|
||||
"InitializeAsync anyway. Check GameContentBootstrap lifecycle logs.");
|
||||
}
|
||||
|
||||
Debug.Log("[Cuong] AddressableManager: Bootstrap gate xong — đang InitializeAsync Addressables...");
|
||||
Addressables.InitializeAsync().Completed += OnInitializeComplete;
|
||||
}
|
||||
|
||||
async UniTask<bool> WaitForBootstrapGateWithTimeoutAsync()
|
||||
{
|
||||
var timeoutSec = Mathf.Max(5f, _bootstrapGateWaitTimeoutSeconds);
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSec));
|
||||
try
|
||||
{
|
||||
await GameContentBootstrap.WaitForPreAddressablesSetupIfAnyAsync(cts.Token);
|
||||
return true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#region Unity lifecycle
|
||||
private List<string> _assetToForceRelease = new();
|
||||
private void Update()
|
||||
|
||||
@@ -64,11 +64,20 @@ namespace BrewMonster.Scripts
|
||||
/// <param name="autoReleaseHandle">Pass through to Addressables (default true).</param>
|
||||
public static async UniTask<CatalogCheckResult> CheckForCatalogUpdatesAsync(bool autoReleaseHandle = true)
|
||||
{
|
||||
AsyncOperationHandle<List<string>> handle = default;
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.CheckForCatalogUpdates(autoReleaseHandle);
|
||||
handle = Addressables.CheckForCatalogUpdates(autoReleaseHandle: false);
|
||||
await handle.ToUniTask();
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
var err = new InvalidOperationException("CheckForCatalogUpdates handle was released before result could be read.");
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: {err.Message}");
|
||||
return new CatalogCheckResult(false, null, err);
|
||||
}
|
||||
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
var err = handle.OperationException;
|
||||
@@ -85,6 +94,10 @@ namespace BrewMonster.Scripts
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CheckForCatalogUpdates exception: {e.Message}");
|
||||
return new CatalogCheckResult(false, null, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseHandleIfNeeded(handle, autoReleaseHandle: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,16 +110,24 @@ namespace BrewMonster.Scripts
|
||||
bool autoCleanBundleCache = false,
|
||||
bool autoReleaseHandle = true)
|
||||
{
|
||||
AsyncOperationHandle<List<IResourceLocator>> handle = default;
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
AsyncOperationHandle<List<IResourceLocator>> handle;
|
||||
if (autoCleanBundleCache)
|
||||
handle = Addressables.UpdateCatalogs(true, catalogIds, autoReleaseHandle);
|
||||
handle = Addressables.UpdateCatalogs(true, catalogIds, autoReleaseHandle: false);
|
||||
else
|
||||
handle = Addressables.UpdateCatalogs(catalogIds, autoReleaseHandle);
|
||||
handle = Addressables.UpdateCatalogs(catalogIds, autoReleaseHandle: false);
|
||||
|
||||
await handle.ToUniTask();
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
var err = new InvalidOperationException("UpdateCatalogs handle was released before result could be read.");
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: {err.Message}");
|
||||
return new CatalogApplyResult(false, null, err);
|
||||
}
|
||||
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
var err = handle.OperationException;
|
||||
@@ -123,6 +144,10 @@ namespace BrewMonster.Scripts
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: UpdateCatalogs exception: {e.Message}");
|
||||
return new CatalogApplyResult(false, null, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseHandleIfNeeded(handle, autoReleaseHandle: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,11 +169,19 @@ namespace BrewMonster.Scripts
|
||||
/// </summary>
|
||||
public static async UniTask<long> GetDownloadSizeBytesAsync(object key)
|
||||
{
|
||||
AsyncOperationHandle<long> handle = default;
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.GetDownloadSizeAsync(key);
|
||||
handle = Addressables.GetDownloadSizeAsync(key);
|
||||
await handle.ToUniTask();
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
BMLogger.LogError("AddressablesCatalogUpdater: GetDownloadSizeAsync handle was released before result could be read.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: GetDownloadSizeAsync failed: {handle.OperationException?.Message}");
|
||||
@@ -161,6 +194,10 @@ namespace BrewMonster.Scripts
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: GetDownloadSizeBytesAsync exception: {e.Message}");
|
||||
return -1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseHandleIfNeeded(handle, autoReleaseHandle: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -168,11 +205,15 @@ namespace BrewMonster.Scripts
|
||||
/// Logs download percent (and MB when known) every <paramref name="progressLogStepPercent"/> percent via <c>[Cuong]</c>.
|
||||
/// </summary>
|
||||
/// <param name="progressLogStepPercent">Log when percent crosses each step (1–100). Default 5.</param>
|
||||
/// <remarks>
|
||||
/// Handle is always retained until this method finishes (autoReleaseHandle forced false) so progress polling
|
||||
/// does not touch a handle Addressables already released on completion.
|
||||
/// </remarks>
|
||||
public static async UniTask<bool> DownloadDependenciesAsync(
|
||||
object key,
|
||||
bool autoReleaseHandle = true,
|
||||
int progressLogStepPercent = 5)
|
||||
{
|
||||
AsyncOperationHandle handle = default;
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
@@ -180,18 +221,30 @@ namespace BrewMonster.Scripts
|
||||
var step = Mathf.Clamp(progressLogStepPercent, 1, 100);
|
||||
Debug.Log($"[Cuong] AddressablesCatalogUpdater: Bắt đầu tải dependencies (key={keyLabel})...");
|
||||
|
||||
var handle = Addressables.DownloadDependenciesAsync(key, autoReleaseHandle);
|
||||
// Never auto-release while polling; caller passing true is ignored to avoid invalid-handle errors.
|
||||
handle = Addressables.DownloadDependenciesAsync(key, autoReleaseHandle: false);
|
||||
var lastLoggedPercent = -1;
|
||||
LogDownloadProgress(keyLabel, handle, ref lastLoggedPercent, step, force: true);
|
||||
|
||||
if (handle.IsValid())
|
||||
LogDownloadProgress(keyLabel, handle, ref lastLoggedPercent, step, force: true);
|
||||
|
||||
while (!handle.IsDone)
|
||||
{
|
||||
LogDownloadProgress(keyLabel, handle, ref lastLoggedPercent, step);
|
||||
if (handle.IsValid())
|
||||
LogDownloadProgress(keyLabel, handle, ref lastLoggedPercent, step);
|
||||
await UniTask.Yield();
|
||||
}
|
||||
|
||||
LogDownloadProgress(keyLabel, handle, ref lastLoggedPercent, step, force: true);
|
||||
await handle.ToUniTask();
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
BMLogger.LogError("AddressablesCatalogUpdater: DownloadDependenciesAsync handle invalid after completion.");
|
||||
Debug.LogError($"[Cuong] AddressablesCatalogUpdater: Handle không hợp lệ sau khi tải '{keyLabel}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handle.IsValid())
|
||||
LogDownloadProgress(keyLabel, handle, ref lastLoggedPercent, step, force: true);
|
||||
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: DownloadDependenciesAsync failed: {handle.OperationException?.Message}");
|
||||
@@ -208,6 +261,17 @@ namespace BrewMonster.Scripts
|
||||
Debug.LogError($"[Cuong] AddressablesCatalogUpdater: Exception khi tải — {e.Message}");
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseHandleIfNeeded(handle, autoReleaseHandle: false);
|
||||
}
|
||||
}
|
||||
|
||||
static void ReleaseHandleIfNeeded(AsyncOperationHandle handle, bool autoReleaseHandle)
|
||||
{
|
||||
if (autoReleaseHandle || !handle.IsValid())
|
||||
return;
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
|
||||
static void LogDownloadProgress(
|
||||
@@ -217,6 +281,9 @@ namespace BrewMonster.Scripts
|
||||
int stepPercent,
|
||||
bool force = false)
|
||||
{
|
||||
if (!handle.IsValid())
|
||||
return;
|
||||
|
||||
var status = handle.GetDownloadStatus();
|
||||
var percent = Mathf.Clamp(status.Percent * 100f, 0f, 100f);
|
||||
var percentRounded = Mathf.RoundToInt(percent);
|
||||
@@ -248,11 +315,19 @@ namespace BrewMonster.Scripts
|
||||
/// </summary>
|
||||
public static async UniTask<bool> CleanBundleCacheAsync(IEnumerable<string> catalogIds = null)
|
||||
{
|
||||
AsyncOperationHandle<bool> handle = default;
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.CleanBundleCache(catalogIds);
|
||||
handle = Addressables.CleanBundleCache(catalogIds);
|
||||
await handle.ToUniTask();
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
BMLogger.LogError("AddressablesCatalogUpdater: CleanBundleCache handle was released before result could be read.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CleanBundleCache failed: {handle.OperationException?.Message}");
|
||||
@@ -265,6 +340,10 @@ namespace BrewMonster.Scripts
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CleanBundleCacheAsync exception: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseHandleIfNeeded(handle, autoReleaseHandle: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using BrewMonster;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
@@ -21,6 +23,17 @@ namespace BrewMonster.Scripts
|
||||
/// When non-null, <see cref="AddressableManager"/> waits on this before <see cref="UnityEngine.AddressableAssets.Addressables.InitializeAsync"/>.
|
||||
/// </summary>
|
||||
static UniTaskCompletionSource s_addressablesInitGate;
|
||||
static int s_activeBootstrapInstanceId;
|
||||
static bool s_bootstrapRunStarted;
|
||||
|
||||
[Header("Debug")]
|
||||
[Tooltip("Log lifecycle (Awake/Start/OnDestroy), gate state, scene name — dùng khi debug mobile.")]
|
||||
[SerializeField]
|
||||
bool _verboseLifecycleDebug = true;
|
||||
|
||||
[Tooltip("Nếu gate chưa mở sau N giây, tự release để AddressableManager không treo vĩnh viễn.")]
|
||||
[SerializeField]
|
||||
float _gateReleaseTimeoutSeconds = 45f;
|
||||
|
||||
[Header("Version source")]
|
||||
[Tooltip("True = gọi HTTP tới URL bên dưới. False = không request server, chỉ dùng hardcode (test / API chưa chốt).")]
|
||||
@@ -76,41 +89,121 @@ namespace BrewMonster.Scripts
|
||||
|
||||
public event Action<BootstrapResult> Finished;
|
||||
|
||||
public static UniTask WaitForPreAddressablesSetupIfAnyAsync()
|
||||
/// <summary>Trạng thái gate tĩnh — dùng log chẩn đoán từ <see cref="AddressableManager"/>.</summary>
|
||||
public static string GetGateDebugState()
|
||||
{
|
||||
if (!_holdAddressablesInitConfigured)
|
||||
return "holdAddressablesInit=false (no gate)";
|
||||
if (s_addressablesInitGate == null)
|
||||
return "gate=null (released or not created)";
|
||||
return $"gate=pending, activeInstanceId={s_activeBootstrapInstanceId}, runStarted={s_bootstrapRunStarted}";
|
||||
}
|
||||
|
||||
static bool _holdAddressablesInitConfigured = true;
|
||||
|
||||
public static UniTask WaitForPreAddressablesSetupIfAnyAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (s_addressablesInitGate == null)
|
||||
return UniTask.CompletedTask;
|
||||
return s_addressablesInitGate.Task;
|
||||
return s_addressablesInitGate.Task.AttachExternalCancellation(cancellationToken);
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
s_activeBootstrapInstanceId = GetInstanceID();
|
||||
_holdAddressablesInitConfigured = _holdAddressablesInitUntilVersionChecked;
|
||||
LogLifecycle("Awake");
|
||||
|
||||
if (_holdAddressablesInitUntilVersionChecked)
|
||||
{
|
||||
s_addressablesInitGate ??= new UniTaskCompletionSource();
|
||||
GateTimeoutWatchdog().Forget();
|
||||
}
|
||||
else
|
||||
LogLifecycle("Awake: holdAddressablesInit=false — AddressableManager will not wait on gate.");
|
||||
|
||||
TryStartBootstrapRun("Awake");
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
RunAsync().Forget();
|
||||
LogLifecycle("Start");
|
||||
TryStartBootstrapRun("Start");
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
ReleaseGateIfPending();
|
||||
LogLifecycle("OnDestroy — releasing gate if still pending");
|
||||
ReleaseGateIfPending("OnDestroy");
|
||||
if (s_activeBootstrapInstanceId == GetInstanceID())
|
||||
s_activeBootstrapInstanceId = 0;
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
ReleaseGateIfPending();
|
||||
LogLifecycle("OnApplicationQuit");
|
||||
ReleaseGateIfPending("OnApplicationQuit");
|
||||
}
|
||||
|
||||
static void ReleaseGateIfPending()
|
||||
void TryStartBootstrapRun(string caller)
|
||||
{
|
||||
if (s_addressablesInitGate != null)
|
||||
if (!isActiveAndEnabled)
|
||||
{
|
||||
s_addressablesInitGate.TrySetResult();
|
||||
s_addressablesInitGate = null;
|
||||
LogLifecycle($"{caller}: SKIP bootstrap — GameObject inactive or component disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_bootstrapRunStarted)
|
||||
{
|
||||
LogLifecycle($"{caller}: bootstrap already started (skip duplicate).");
|
||||
return;
|
||||
}
|
||||
|
||||
s_bootstrapRunStarted = true;
|
||||
LogLifecycle($"{caller}: starting RunAsync.");
|
||||
RunAsync().Forget();
|
||||
}
|
||||
|
||||
async UniTaskVoid GateTimeoutWatchdog()
|
||||
{
|
||||
var timeout = Mathf.Max(5f, _gateReleaseTimeoutSeconds);
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(timeout));
|
||||
|
||||
if (s_addressablesInitGate == null)
|
||||
return;
|
||||
|
||||
Debug.LogWarning(
|
||||
$"[Cuong] GameContentBootstrap: Gate timeout ({timeout:F0}s) — releasing gate. " +
|
||||
$"runStarted={s_bootstrapRunStarted}, scene={SceneManager.GetActiveScene().name}, {DescribeSelf()}");
|
||||
AllowAddressablesInit("GateTimeoutWatchdog");
|
||||
}
|
||||
|
||||
static void ReleaseGateIfPending(string reason)
|
||||
{
|
||||
if (s_addressablesInitGate == null)
|
||||
return;
|
||||
|
||||
Debug.LogWarning(
|
||||
$"[Cuong] GameContentBootstrap: ReleaseGate ({reason}) — gate opened without normal bootstrap completion.");
|
||||
s_addressablesInitGate.TrySetResult();
|
||||
s_addressablesInitGate = null;
|
||||
}
|
||||
|
||||
void LogLifecycle(string phase)
|
||||
{
|
||||
if (!_verboseLifecycleDebug)
|
||||
return;
|
||||
|
||||
Debug.Log(
|
||||
$"[Cuong] GameContentBootstrap: {phase} | {DescribeSelf()} | gate={GetGateDebugState()} | " +
|
||||
$"scene={SceneManager.GetActiveScene().name} frame={Time.frameCount}");
|
||||
}
|
||||
|
||||
string DescribeSelf()
|
||||
{
|
||||
return
|
||||
$"id={GetInstanceID()} active={gameObject.activeInHierarchy} enabled={enabled} " +
|
||||
$"holdInit={_holdAddressablesInitUntilVersionChecked} server={_useServerForVersionInfo}";
|
||||
}
|
||||
|
||||
async UniTaskVoid RunAsync()
|
||||
@@ -130,7 +223,7 @@ namespace BrewMonster.Scripts
|
||||
if (!fetch.Ok)
|
||||
{
|
||||
Debug.LogError($"[Cuong] GameContentBootstrap: Lỗi lấy version — {fetch.Error}");
|
||||
AllowAddressablesInit();
|
||||
AllowAddressablesInit("version-fetch-failed");
|
||||
return new BootstrapResult(false, false, fetch.Error, null);
|
||||
}
|
||||
|
||||
@@ -146,7 +239,7 @@ namespace BrewMonster.Scripts
|
||||
Debug.Log("[Cuong] GameContentBootstrap: Đã gắn URL rewrite cho remote CDN.");
|
||||
}
|
||||
|
||||
AllowAddressablesInit();
|
||||
AllowAddressablesInit("version-and-url-ready");
|
||||
|
||||
Debug.Log("[Cuong] GameContentBootstrap: Đang khởi tạo Addressables...");
|
||||
await AddressablesCatalogUpdater.EnsureInitializedAsync();
|
||||
@@ -201,7 +294,7 @@ namespace BrewMonster.Scripts
|
||||
$"[Cuong] GameContentBootstrap: Đang tải remote content (label={bulkLabel}) — không lấy được dung lượng trước khi tải.");
|
||||
}
|
||||
|
||||
bool dl = await AddressablesCatalogUpdater.DownloadDependenciesAsync(bulkLabel, true);
|
||||
bool dl = await AddressablesCatalogUpdater.DownloadDependenciesAsync(bulkLabel);
|
||||
if (!dl)
|
||||
{
|
||||
Debug.LogError("[Cuong] GameContentBootstrap: Tải remote content thất bại.");
|
||||
@@ -220,18 +313,22 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
BMLogger.LogError($"[Cuong] GameContentBootstrap: {e.Message}");
|
||||
Debug.LogError($"[Cuong] GameContentBootstrap: Exception — {e.Message}");
|
||||
AllowAddressablesInit();
|
||||
AllowAddressablesInit("exception");
|
||||
return new BootstrapResult(false, true, e.Message, null);
|
||||
}
|
||||
}
|
||||
|
||||
static void AllowAddressablesInit()
|
||||
static void AllowAddressablesInit(string reason)
|
||||
{
|
||||
if (s_addressablesInitGate != null)
|
||||
if (s_addressablesInitGate == null)
|
||||
{
|
||||
s_addressablesInitGate.TrySetResult();
|
||||
s_addressablesInitGate = null;
|
||||
Debug.Log($"[Cuong] GameContentBootstrap: AllowAddressablesInit({reason}) — gate already null.");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"[Cuong] GameContentBootstrap: AllowAddressablesInit({reason}) — opening gate for AddressableManager.");
|
||||
s_addressablesInitGate.TrySetResult();
|
||||
s_addressablesInitGate = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user