update logic download to cnd with addressable
This commit is contained in:
@@ -53,6 +53,15 @@ namespace BrewMonster.Scripts
|
||||
base.Initialize();
|
||||
_isInitialized = false;
|
||||
_initializationTcs = new UniTaskCompletionSource();
|
||||
StartAddressablesInitAfterBootstrapGate().Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for <see cref="GameContentBootstrap"/> (version HTTP + optional URL rewrite) when that gate is active.
|
||||
/// </summary>
|
||||
async UniTaskVoid StartAddressablesInitAfterBootstrapGate()
|
||||
{
|
||||
await GameContentBootstrap.WaitForPreAddressablesSetupIfAnyAsync();
|
||||
Addressables.InitializeAsync().Completed += OnInitializeComplete;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BrewMonster;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.AddressableAssets.ResourceLocators;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Remote catalog / bundle flows: CheckForCatalogUpdates, UpdateCatalogs, optional download size and dependencies.
|
||||
/// Matches the “catalog new → bundle new / cache” behaviour described in project docs (Addressables overview).
|
||||
/// </summary>
|
||||
public static class AddressablesCatalogUpdater
|
||||
{
|
||||
/// <summary>
|
||||
/// Result of checking the remote catalog hash list (may be empty when nothing changed).
|
||||
/// </summary>
|
||||
public readonly struct CatalogCheckResult
|
||||
{
|
||||
public CatalogCheckResult(bool success, IReadOnlyList<string> catalogsWithUpdates, Exception error)
|
||||
{
|
||||
Success = success;
|
||||
CatalogsWithUpdates = catalogsWithUpdates ?? Array.Empty<string>();
|
||||
Error = error;
|
||||
}
|
||||
|
||||
public bool Success { get; }
|
||||
public IReadOnlyList<string> CatalogsWithUpdates { get; }
|
||||
public bool HasUpdates => CatalogsWithUpdates.Count > 0;
|
||||
public Exception Error { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result after applying <see cref="Addressables.UpdateCatalogs"/>.
|
||||
/// </summary>
|
||||
public readonly struct CatalogApplyResult
|
||||
{
|
||||
public CatalogApplyResult(bool success, IReadOnlyList<IResourceLocator> locators, Exception error)
|
||||
{
|
||||
Success = success;
|
||||
Locators = locators ?? Array.Empty<IResourceLocator>();
|
||||
Error = error;
|
||||
}
|
||||
|
||||
public bool Success { get; }
|
||||
public IReadOnlyList<IResourceLocator> Locators { get; }
|
||||
public Exception Error { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures Addressables finished initial catalog load before checking remote updates.
|
||||
/// </summary>
|
||||
public static async UniTask EnsureInitializedAsync()
|
||||
{
|
||||
await Addressables.InitializeAsync().ToUniTask();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="Addressables.CheckForCatalogUpdates"/> — lightweight compared to full bundle downloads.
|
||||
/// </summary>
|
||||
/// <param name="autoReleaseHandle">Pass through to Addressables (default true).</param>
|
||||
public static async UniTask<CatalogCheckResult> CheckForCatalogUpdatesAsync(bool autoReleaseHandle = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.CheckForCatalogUpdates(autoReleaseHandle);
|
||||
await handle.ToUniTask();
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
var err = handle.OperationException;
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CheckForCatalogUpdates failed: {err?.Message}");
|
||||
return new CatalogCheckResult(false, null, err);
|
||||
}
|
||||
|
||||
var list = handle.Result;
|
||||
var ids = list != null ? (IReadOnlyList<string>)list : Array.Empty<string>();
|
||||
return new CatalogCheckResult(true, ids, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CheckForCatalogUpdates exception: {e.Message}");
|
||||
return new CatalogCheckResult(false, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads new catalog JSON and refreshes locators. Pass <paramref name="catalogIds"/> from
|
||||
/// <see cref="CatalogCheckResult.CatalogsWithUpdates"/> or null to use Addressables’ internal list.
|
||||
/// </summary>
|
||||
/// <param name="autoCleanBundleCache">When true, removes unreferenced bundles after update (see Addressables docs).</param>
|
||||
public static async UniTask<CatalogApplyResult> UpdateCatalogsAsync(
|
||||
IEnumerable<string> catalogIds = null,
|
||||
bool autoCleanBundleCache = false,
|
||||
bool autoReleaseHandle = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
AsyncOperationHandle<List<IResourceLocator>> handle;
|
||||
if (autoCleanBundleCache)
|
||||
handle = Addressables.UpdateCatalogs(true, catalogIds, autoReleaseHandle);
|
||||
else
|
||||
handle = Addressables.UpdateCatalogs(catalogIds, autoReleaseHandle);
|
||||
|
||||
await handle.ToUniTask();
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
var err = handle.OperationException;
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: UpdateCatalogs failed: {err?.Message}");
|
||||
return new CatalogApplyResult(false, null, err);
|
||||
}
|
||||
|
||||
var locators = handle.Result;
|
||||
var read = locators != null ? (IReadOnlyList<IResourceLocator>)locators : Array.Empty<IResourceLocator>();
|
||||
return new CatalogApplyResult(true, read, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: UpdateCatalogs exception: {e.Message}");
|
||||
return new CatalogApplyResult(false, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check remote catalog, then apply updates if any catalog ids were returned.
|
||||
/// </summary>
|
||||
public static async UniTask<CatalogApplyResult> CheckAndUpdateCatalogsIfNeededAsync(bool autoCleanBundleCache = false)
|
||||
{
|
||||
var check = await CheckForCatalogUpdatesAsync(true);
|
||||
if (!check.Success)
|
||||
return new CatalogApplyResult(false, null, check.Error);
|
||||
if (!check.HasUpdates)
|
||||
return new CatalogApplyResult(true, Array.Empty<IResourceLocator>(), null);
|
||||
|
||||
return await UpdateCatalogsAsync(check.CatalogsWithUpdates, autoCleanBundleCache, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bytes that would be downloaded for <paramref name="key"/> given the current catalog and local cache (0 if fully cached).
|
||||
/// </summary>
|
||||
public static async UniTask<long> GetDownloadSizeBytesAsync(object key)
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.GetDownloadSizeAsync(key);
|
||||
await handle.ToUniTask();
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: GetDownloadSizeAsync failed: {handle.OperationException?.Message}");
|
||||
return -1;
|
||||
}
|
||||
return handle.Result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: GetDownloadSizeBytesAsync exception: {e.Message}");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures dependencies for <paramref name="key"/> exist on disk; uses cache when CRC/catalog match (no redundant full download).
|
||||
/// </summary>
|
||||
public static async UniTask<bool> DownloadDependenciesAsync(object key, bool autoReleaseHandle = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.DownloadDependenciesAsync(key, autoReleaseHandle);
|
||||
await handle.ToUniTask();
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: DownloadDependenciesAsync failed: {handle.OperationException?.Message}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: DownloadDependenciesAsync exception: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes bundles not referenced by the given catalogs (optional maintenance / “clear old cache”).
|
||||
/// </summary>
|
||||
public static async UniTask<bool> CleanBundleCacheAsync(IEnumerable<string> catalogIds = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
var handle = Addressables.CleanBundleCache(catalogIds);
|
||||
await handle.ToUniTask();
|
||||
if (handle.Status != AsyncOperationStatus.Succeeded)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CleanBundleCache failed: {handle.OperationException?.Message}");
|
||||
return false;
|
||||
}
|
||||
return handle.Result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BMLogger.LogError($"AddressablesCatalogUpdater: CleanBundleCacheAsync exception: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e0ec4bd4b83dbd488a581d5288a5e52
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using BrewMonster;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Runtime rewrite of bundle/catalog URLs via <see cref="Addressables.InternalIdTransformFunc"/>
|
||||
/// (e.g. swap CDN host or path prefix). Must run before the first successful remote load — ideally before
|
||||
/// <see cref="Addressables.InitializeAsync"/> if all remote ids should be rewritten.
|
||||
/// </summary>
|
||||
public static class AddressablesRuntimeUrlRewriter
|
||||
{
|
||||
static Func<IResourceLocation, string> s_previousTransform;
|
||||
static string s_fromPrefix;
|
||||
static string s_toPrefix;
|
||||
|
||||
/// <summary>
|
||||
/// When true, the installed rewriter calls the previous <see cref="Addressables.InternalIdTransformFunc"/> first.
|
||||
/// </summary>
|
||||
public static bool ChainPreviousTransform { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the start of each location’s <see cref="IResourceLocation.InternalId"/> when it begins with
|
||||
/// <paramref name="fromPrefix"/> (e.g. build-time profile URL) by <paramref name="toPrefix"/> (runtime CDN).
|
||||
/// </summary>
|
||||
public static void InstallPrefixRewrite(string fromPrefix, string toPrefix)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fromPrefix))
|
||||
{
|
||||
BMLogger.LogError("AddressablesRuntimeUrlRewriter: fromPrefix is null or empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
s_fromPrefix = fromPrefix;
|
||||
s_toPrefix = toPrefix ?? string.Empty;
|
||||
|
||||
if (ChainPreviousTransform)
|
||||
s_previousTransform = Addressables.InternalIdTransformFunc;
|
||||
|
||||
Addressables.InternalIdTransformFunc = Transform;
|
||||
BMLogger.Log($"AddressablesRuntimeUrlRewriter: Installed prefix rewrite (from length={fromPrefix.Length}, to length={s_toPrefix.Length}).");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes this package’s rewrite and restores the delegate that was present at install time (if any).
|
||||
/// </summary>
|
||||
public static void ClearInstalledRewrite()
|
||||
{
|
||||
if (Addressables.InternalIdTransformFunc == Transform)
|
||||
{
|
||||
Addressables.InternalIdTransformFunc = s_previousTransform;
|
||||
s_previousTransform = null;
|
||||
s_fromPrefix = null;
|
||||
s_toPrefix = null;
|
||||
BMLogger.Log("AddressablesRuntimeUrlRewriter: Cleared installed rewrite.");
|
||||
}
|
||||
}
|
||||
|
||||
static string Transform(IResourceLocation location)
|
||||
{
|
||||
string id = location != null ? location.InternalId : null;
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return id;
|
||||
|
||||
if (ChainPreviousTransform && s_previousTransform != null)
|
||||
id = s_previousTransform(location);
|
||||
|
||||
if (!string.IsNullOrEmpty(s_fromPrefix) &&
|
||||
id.StartsWith(s_fromPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return s_toPrefix + id.Substring(s_fromPrefix.Length);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57d28e0e103bc3743a57b12f74be99ae
|
||||
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using BrewMonster;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Bootstrap: gọi server lấy contentVersion + (tuỳ chọn) assetsBaseUrl, 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: call server for contentVersion + optional assetsBaseUrl, apply URL rewrite before Addressables init,
|
||||
/// then if first launch or stored version differs, update catalogs and download all entries under the configured label.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-2000)]
|
||||
public class GameContentBootstrap : MonoBehaviour
|
||||
{
|
||||
const string PrefsFirstSyncDone = "PW_GameContent_FirstRemoteSyncDone";
|
||||
const string PrefsLastContentVersion = "PW_GameContent_LastContentVersion";
|
||||
|
||||
/// <summary>
|
||||
/// When non-null, <see cref="AddressableManager"/> waits on this before <see cref="UnityEngine.AddressableAssets.Addressables.InitializeAsync"/>.
|
||||
/// </summary>
|
||||
static UniTaskCompletionSource s_addressablesInitGate;
|
||||
|
||||
[Header("Version API")]
|
||||
[Tooltip("GET JSON: { \"contentVersion\": \"12\", \"assetsBaseUrl\": \"https://cdn/.../\" }")]
|
||||
[SerializeField] string _versionEndpointUrl;
|
||||
|
||||
[SerializeField] int _requestTimeoutSeconds = 20;
|
||||
|
||||
[Header("Addressables")]
|
||||
[Tooltip("If true, blocks Addressables init until version HTTP + optional URL rewrite finish (recommended).")]
|
||||
[SerializeField] bool _holdAddressablesInitUntilVersionChecked = true;
|
||||
|
||||
[Tooltip("Prefix baked into remote InternalIds at build (Remote.LoadPath). When server sends assetsBaseUrl, replace this prefix.")]
|
||||
[SerializeField] string _bakedRemoteUrlPrefixForRewrite;
|
||||
|
||||
[Tooltip("Label applied in Addressables Groups to every remote asset that must download on first run / content update.")]
|
||||
[SerializeField] string _remoteBulkDownloadLabel = "RemoteContent";
|
||||
|
||||
[Header("Editor")]
|
||||
[SerializeField] bool _skipRemoteCallInEditor;
|
||||
|
||||
[SerializeField] string _editorFakeContentVersion = "editor";
|
||||
|
||||
public event Action<BootstrapResult> Finished;
|
||||
|
||||
public static UniTask WaitForPreAddressablesSetupIfAnyAsync()
|
||||
{
|
||||
if (s_addressablesInitGate == null)
|
||||
return UniTask.CompletedTask;
|
||||
return s_addressablesInitGate.Task;
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (_holdAddressablesInitUntilVersionChecked)
|
||||
s_addressablesInitGate ??= new UniTaskCompletionSource();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
RunAsync().Forget();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
ReleaseGateIfPending();
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
ReleaseGateIfPending();
|
||||
}
|
||||
|
||||
static void ReleaseGateIfPending()
|
||||
{
|
||||
if (s_addressablesInitGate != null)
|
||||
{
|
||||
s_addressablesInitGate.TrySetResult();
|
||||
s_addressablesInitGate = null;
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunAsync()
|
||||
{
|
||||
var result = await RunInternalAsync();
|
||||
Finished?.Invoke(result);
|
||||
}
|
||||
|
||||
public async UniTask<BootstrapResult> RunInternalAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var dto = await FetchVersionDtoAsync();
|
||||
if (!dto.Ok)
|
||||
{
|
||||
AllowAddressablesInit();
|
||||
return new BootstrapResult(false, false, dto.Error, null);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(dto.AssetsBaseUrl) &&
|
||||
!string.IsNullOrWhiteSpace(_bakedRemoteUrlPrefixForRewrite))
|
||||
{
|
||||
AddressablesRuntimeUrlRewriter.InstallPrefixRewrite(
|
||||
_bakedRemoteUrlPrefixForRewrite,
|
||||
dto.AssetsBaseUrl);
|
||||
}
|
||||
|
||||
AllowAddressablesInit();
|
||||
|
||||
await AddressablesCatalogUpdater.EnsureInitializedAsync();
|
||||
|
||||
bool firstRun = PlayerPrefs.GetInt(PrefsFirstSyncDone, 0) == 0;
|
||||
string localVersion = PlayerPrefs.GetString(PrefsLastContentVersion, string.Empty);
|
||||
bool needContentWork =
|
||||
firstRun ||
|
||||
!string.Equals(localVersion, dto.ContentVersion ?? string.Empty, StringComparison.Ordinal);
|
||||
|
||||
if (!needContentWork)
|
||||
{
|
||||
BMLogger.Log("[Cuong] GameContentBootstrap: contentVersion unchanged, skip catalog/bulk download.");
|
||||
return new BootstrapResult(true, false, null, dto.ContentVersion);
|
||||
}
|
||||
|
||||
var catalog = await AddressablesCatalogUpdater.CheckAndUpdateCatalogsIfNeededAsync(false);
|
||||
if (!catalog.Success)
|
||||
return new BootstrapResult(false, true, catalog.Error?.Message ?? "Catalog update failed", dto.ContentVersion);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_remoteBulkDownloadLabel))
|
||||
{
|
||||
BMLogger.LogError("[Cuong] GameContentBootstrap: _remoteBulkDownloadLabel is empty; skipping bulk download.");
|
||||
return new BootstrapResult(false, true, "remoteBulkDownloadLabel empty", dto.ContentVersion);
|
||||
}
|
||||
|
||||
bool dl = await AddressablesCatalogUpdater.DownloadDependenciesAsync(_remoteBulkDownloadLabel.Trim(), true);
|
||||
if (!dl)
|
||||
return new BootstrapResult(false, true, "DownloadDependencies failed", dto.ContentVersion);
|
||||
|
||||
PlayerPrefs.SetString(PrefsLastContentVersion, dto.ContentVersion);
|
||||
PlayerPrefs.SetInt(PrefsFirstSyncDone, 1);
|
||||
PlayerPrefs.Save();
|
||||
|
||||
BMLogger.Log($"[Cuong] GameContentBootstrap: content sync OK, version={dto.ContentVersion}");
|
||||
return new BootstrapResult(true, true, null, dto.ContentVersion);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BMLogger.LogError($"[Cuong] GameContentBootstrap: {e.Message}");
|
||||
AllowAddressablesInit();
|
||||
return new BootstrapResult(false, true, e.Message, null);
|
||||
}
|
||||
}
|
||||
|
||||
static void AllowAddressablesInit()
|
||||
{
|
||||
if (s_addressablesInitGate != null)
|
||||
{
|
||||
s_addressablesInitGate.TrySetResult();
|
||||
s_addressablesInitGate = null;
|
||||
}
|
||||
}
|
||||
|
||||
async UniTask<VersionDtoResult> FetchVersionDtoAsync()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (_skipRemoteCallInEditor)
|
||||
{
|
||||
return new VersionDtoResult(true, _editorFakeContentVersion?.Trim() ?? "editor", null, null);
|
||||
}
|
||||
#endif
|
||||
if (string.IsNullOrWhiteSpace(_versionEndpointUrl))
|
||||
{
|
||||
BMLogger.LogWarning("[Cuong] GameContentBootstrap: _versionEndpointUrl empty; using empty contentVersion (no remote check).");
|
||||
return new VersionDtoResult(true, string.Empty, null, null);
|
||||
}
|
||||
|
||||
using var req = UnityWebRequest.Get(_versionEndpointUrl);
|
||||
req.timeout = Mathf.Max(5, _requestTimeoutSeconds);
|
||||
await req.SendWebRequest().ToUniTask();
|
||||
|
||||
if (req.result != UnityWebRequest.Result.Success)
|
||||
return new VersionDtoResult(false, null, null, req.error);
|
||||
|
||||
string json = req.downloadHandler?.text;
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return new VersionDtoResult(false, null, null, "Empty response body");
|
||||
|
||||
try
|
||||
{
|
||||
var parsed = JsonUtility.FromJson<VersionResponseJson>(json);
|
||||
if (parsed == null || string.IsNullOrWhiteSpace(parsed.contentVersion))
|
||||
return new VersionDtoResult(false, null, null, "JSON missing contentVersion");
|
||||
|
||||
return new VersionDtoResult(true, parsed.contentVersion.Trim(), parsed.assetsBaseUrl?.Trim(), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new VersionDtoResult(false, null, null, $"JSON parse: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
readonly struct VersionDtoResult
|
||||
{
|
||||
public VersionDtoResult(bool ok, string contentVersion, string assetsBaseUrl, string error)
|
||||
{
|
||||
Ok = ok;
|
||||
ContentVersion = contentVersion;
|
||||
AssetsBaseUrl = assetsBaseUrl;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
public bool Ok { get; }
|
||||
public string ContentVersion { get; }
|
||||
public string AssetsBaseUrl { get; }
|
||||
public string Error { get; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class VersionResponseJson
|
||||
{
|
||||
public string contentVersion;
|
||||
public string assetsBaseUrl;
|
||||
}
|
||||
|
||||
public readonly struct BootstrapResult
|
||||
{
|
||||
public BootstrapResult(bool success, bool didContentWork, string errorMessage, string serverContentVersion)
|
||||
{
|
||||
Success = success;
|
||||
DidContentWork = didContentWork;
|
||||
ErrorMessage = errorMessage;
|
||||
ServerContentVersion = serverContentVersion;
|
||||
}
|
||||
|
||||
public bool Success { get; }
|
||||
/// <summary>True if catalog/bulk download ran this session.</summary>
|
||||
public bool DidContentWork { get; }
|
||||
public string ErrorMessage { get; }
|
||||
public string ServerContentVersion { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d93de6847f714b43830673032ac76d8
|
||||
Reference in New Issue
Block a user