/// <inheritdoc />
        public async Task <IPrefabContentResourceHandle> LoadAvatarPrefabAsync(long avatarId)
        {
            //If it's already available, we can just return immediately
            if (IsAvatarResourceAvailable(avatarId))
            {
                return(TryLoadAvatarPrefab(avatarId));
            }

            ContentDownloadURLResponse downloadUrlResponse = await ContentClient.RequestAvatarDownloadUrl(avatarId, AuthTokenRepo.RetrieveWithType())
                                                             .ConfigureAwait(false);

            //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, 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 (IsAvatarResourceAvailable(avatarId))
                    {
                        completionSource.SetResult(TryLoadAvatarPrefab(avatarId));
                        return;
                    }

                    //otherwise, we still don't have it so we should initialize it.
                    this.ResourceHandleCache[avatarId] = new ReferenceCountedPrefabContentResourceHandle(DownloadHandlerAssetBundle.GetContent(asyncOperation.webRequest));
                    completionSource.SetResult(TryLoadAvatarPrefab(avatarId));                     //we assume this will work now.
                }
            };

            return(await completionSource.Task
                   .ConfigureAwait(false));
        }
示例#2
0
        //TODO: Refactor this behind its own object to provide download URL for character.
        /// <inheritdoc />
        public async Task OnGameInitialized()
        {
            if (Logger.IsInfoEnabled)
            {
                Logger.Info("About to start downloading map data.");
            }

            //When we start the loading screen for the game
            //To know what world we should load we should
            CharacterSessionDataResponse characterSessionData = await CharacterService.GetCharacterSessionData(LocalCharacterData.CharacterId, AuthTokenRepo.RetrieveWithType())
                                                                .ConfigureAwait(false);

            if (!characterSessionData.isSuccessful)
            {
                Logger.Error($"Failed to query Character Session Data: {characterSessionData.ResultCode}:{(int)characterSessionData.ResultCode}");
                return;
            }

            //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.
            long worldId = await ZoneDataService.GetZoneWorld(characterSessionData.ZoneId)
                           .ConfigureAwait(false);

            //With the worldid we can get the download URL.
            ContentDownloadURLResponse urlDownloadResponse = await ContentService.RequestWorldDownloadUrl(worldId, AuthTokenRepo.RetrieveWithType())
                                                             .ConfigureAwait(false);

            //TODO: Handle failure
            if (urlDownloadResponse.isSuccessful)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Download URL: {urlDownloadResponse.DownloadURL}");
                }

                //Can't do web request not on the main thread, sadly.
                await new UnityYieldAwaitable();

                //TODO: Do we need to be on the main unity3d thread
                UnityWebRequestAsyncOperation asyncOperation = UnityWebRequestAssetBundle.GetAssetBundle(urlDownloadResponse.DownloadURL, 0).SendWebRequest();

                //TODO: We should render these operations to the loading screen UI.
                asyncOperation.completed += operation =>
                {
                    AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(asyncOperation.webRequest);

                    string[] paths = bundle.GetAllScenePaths();

                    foreach (string p in paths)
                    {
                        Debug.Log($"Found Scene in Bundle: {p}");
                    }

                    AsyncOperation sceneAsync = SceneManager.LoadSceneAsync(System.IO.Path.GetFileNameWithoutExtension(paths.First()));

                    sceneAsync.completed += operation1 =>
                    {
                        //When the scene is finished loading we should cleanup the asset bundle
                        //Don't clean up the WHOLE BUNDLE, just the compressed downloaded data
                        bundle.Unload(false);

                        //TODO: We need a way/system to reference the bundle later so it can be cleaned up inbetween scene loads.
                    };

                    sceneAsync.allowSceneActivation = true;
                };
            }
        }