protected override void OnThreadUnSafeEventFired(object source, CharacterSessionDataChangedEventArgs args) { if (Logger.IsInfoEnabled) { Logger.Info($"Starting process to download world."); } UnityAsyncHelper.UnityMainThreadContext.PostAsync(async() => { long worldId = 0; try { //TODO: Handle failure ProjectVersionStage.AssertAlpha(); //TODO: Handle throwing/error //We need to know the world the zone is it, so we can request a download URL for it. var worldConfig = await ZoneDataService.GetZoneWorldConfigurationAsync(args.ZoneIdentifier) .ConfigureAwaitFalse(); if (!worldConfig.isSuccessful) { throw new InvalidOperationException($"Failed to query World Configuration for ZoneId: {args.ZoneIdentifier}"); } worldId = worldConfig.Result.WorldId; //With the worldid we can get the download URL. ContentDownloadURLResponse urlDownloadResponse = await ContentService.RequestWorldDownloadUrl(worldId) .ConfigureAwaitFalse(); if (Logger.IsInfoEnabled) { Logger.Info($"World Download Url: {urlDownloadResponse.DownloadURL}"); } //Can't do web request not on the main thread, sadly. await new UnityYieldAwaitable(); WorldDownloader downloader = new WorldDownloader(Logger); await downloader.DownloadAsync(urlDownloadResponse.DownloadURL, urlDownloadResponse.Version, o => { OnWorldDownloadBegins?.Invoke(this, new WorldDownloadBeginEventArgs(o)); }); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Failed to query for Download URL for ZoneId: {args.ZoneIdentifier} WorldId: {worldId} (0 if never succeeded request). Error: {e.Message}"); } throw; } }); }
public async Task OnGameInitialized() { //TODO: Handle throwing/error ContentDownloadURLResponse downloadUrlResponse = await ContentService.RequestWorldDownloadUrl(WorldConfig.WorldId) .ConfigureAwaitFalse(); if (Logger.IsInfoEnabled) { Logger.Info($"World Download Url: {downloadUrlResponse.DownloadURL}"); } //Can't do web request not on the main thread, sadly. await new UnityYieldAwaitable(); //TODO: Handle failure. WorldDownloader downloader = new WorldDownloader(Logger); //At this point after this finishes the world shoud be downloaded. await downloader.DownloadAsync(downloadUrlResponse.DownloadURL, downloadUrlResponse.Version, null, true); //important that the world loads ontop of the existing scene. }
/// <inheritdoc /> public async Task <IPrefabContentResourceHandle> LoadContentPrefabAsync(long contentId) { //If it's already available, we can just return immediately if (IsContentResourceAvailable(contentId)) { return(TryLoadContentPrefab(contentId)); } ContentDownloadURLResponse downloadUrlResponse = await RequestDownloadURL(contentId); //TODO: Handle failure TaskCompletionSource <IPrefabContentResourceHandle> completionSource = new TaskCompletionSource <IPrefabContentResourceHandle>(); //Asset bundle requests can sadly only happen on the main thread, so we must join the main thread. await new UnityYieldAwaitable(); //TODO: We should handle caching, versioning and etc here. UnityWebRequestAsyncOperation asyncOperation = UnityWebRequestAssetBundle.GetAssetBundle(downloadUrlResponse.DownloadURL, (uint)downloadUrlResponse.Version, 0).SendWebRequest(); //TODO: We should render these operations to the loading screen UI. asyncOperation.completed += operation => { //When we first get back on the main thread, the main concern //is that this resource manager may be from the last scene //and that the client may have moved on //to avoid this issues we check disposal state //and do nothing, otherwise if we check AFTER then we just have to release the assetbundle immediately anyway. if (isDisposed) { //Just tell anyone awaiting this that it is canceled. They should handle that case, not us. completionSource.SetCanceled(); return; } //GetContent will throw if the assetbundle has already been loaded. //So to prevent this from occuring due to multiple requests for the //content async we will check, on this main thread, via a write lock. lock (SyncObj) { //We're on the main thread again. So, we should check if another //request already got the bundle if (IsContentResourceAvailable(contentId)) { completionSource.SetResult(TryLoadContentPrefab(contentId)); return; } try { //otherwise, we still don't have it so we should initialize it. this.ResourceHandleCache[contentId] = new ReferenceCountedPrefabContentResourceHandle(DownloadHandlerAssetBundle.GetContent(asyncOperation.webRequest)); completionSource.SetResult(TryLoadContentPrefab(contentId)); //we assume this will work now. } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Failed to load AssetBundle for Content: {contentId}. Reason: {e.ToString()}"); } //Don't rethrow, causing build breaking. } } }; return(await completionSource.Task .ConfigureAwaitFalse()); }