public SceneBundleHandle StealBundle()
        {
            SceneBundleHandle sceneBundleHandle = _SceneBundleHandle;

            _SceneBundleHandle = null;
            return(sceneBundleHandle);
        }
        private static void ReleaseBundle(SceneBundleHandle sceneBundleHandle)
        {
            var bundlePath = sceneBundleHandle._bundlePath;

            if (UnloadingBundles.ContainsKey(bundlePath))
            {
                throw new InvalidOperationException($"Attempting to release a bundle that is already unloading! {bundlePath}");
            }

            if (!LoadedBundles.ContainsKey(bundlePath))
            {
                throw new InvalidOperationException($"Attempting to release a bundle is not contained within LoadedBundles! {bundlePath}");
            }

            LoadedBundles.Remove(bundlePath);
            UnloadingBundles[bundlePath] = sceneBundleHandle;
        }
        private void UpdateBlocking()
        {
            if (_LoadingStatus == LoadingStatus.Completed)
            {
                return;
            }
            if (_SceneSize == 0)
            {
                return;
            }

            try
            {
                _StartTime = Time.realtimeSinceStartup;

                _FileContent = (byte *)UnsafeUtility.Malloc(_SceneSize, 16, Allocator.Persistent);

                ReadCommand cmd;
                cmd.Buffer  = _FileContent;
                cmd.Offset  = 0;
                cmd.Size    = _SceneSize;
                _ReadHandle = AsyncReadManager.Read(_ScenePath, &cmd, 1);

                if (_ExpectedObjectReferenceCount != 0)
                {
#if UNITY_EDITOR
                    var resourceRequests = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(_ResourcesPathObjRefs);
                    _ResourceObjRefs = (ReferencedUnityObjects)resourceRequests[0];
#else
                    _SceneBundleHandle = SceneBundleHandle.CreateOrRetainBundle(_ResourcesPathObjRefs);
                    _ResourceObjRefs   = _SceneBundleHandle.AssetBundle.LoadAsset <ReferencedUnityObjects>(Path.GetFileName(_ResourcesPathObjRefs));
#endif
                }

                ScheduleSceneRead(_ResourceObjRefs);
                _EntityManager.ExclusiveEntityTransactionDependency.Complete();
            }
            catch (Exception e)
            {
                _LoadingFailure = e.Message;
            }
            _LoadingStatus = LoadingStatus.Completed;
        }
Example #4
0
        internal static SceneBundleHandle[] LoadSceneBundles(string mainBundlePath, NativeArray <Entities.Hash128> sharedBundles, bool blocking)
        {
            var hasMainBundle = !string.IsNullOrEmpty(mainBundlePath);
            var bundles       = new SceneBundleHandle[sharedBundles.Length + (hasMainBundle ? 1 : 0)];

            if (hasMainBundle)
            {
                LogBundle($"Request main bundle {mainBundlePath}");
            }

            if (sharedBundles.IsCreated)
            {
                for (int i = 0; i < sharedBundles.Length; i++)
                {
                    var path = $"{Application.streamingAssetsPath}/{EntityScenesPaths.RelativePathFolderFor(sharedBundles[i], EntityScenesPaths.PathType.EntitiesSharedReferencesBundle, -1)}";
                    LogBundle($"Request dependency {mainBundlePath}");
                    bundles[i + 1] = CreateOrRetainBundle(path);
                }
            }

            if (hasMainBundle)
            {
                bundles[0] = CreateOrRetainBundle(mainBundlePath);
            }

            if (blocking)
            {
                foreach (var b in bundles)
                {
                    var forceLoad = b.AssetBundle;
                    if (forceLoad == null)
                    {
                        Debug.LogWarning($"Failed to load asset bundle at path {b._bundlePath}");
                    }
                }
            }
            return(bundles);
        }
        internal static SceneBundleHandle CreateOrRetainBundle(string bundlePath)
        {
            if (bundlePath == null)
            {
                throw new InvalidOperationException("Bundle Path is null!");
            }

            // First Check if we have it loaded
            if (!LoadedBundles.TryGetValue(bundlePath, out var assetBundleHandle))
            {
                // Check if it's about to be unloaded
                if (!UnloadingBundles.TryRemove(bundlePath, out assetBundleHandle))
                {
                    assetBundleHandle = new SceneBundleHandle(bundlePath);
                }

                LoadedBundles[bundlePath] = assetBundleHandle;
            }

            assetBundleHandle.Retain();

            return(assetBundleHandle);
        }
        private void UpdateAsync()
        {
            //@TODO: Try to overlap Resources load and entities scene load

            // Begin Async resource load
            if (_LoadingStatus == LoadingStatus.NotStarted)
            {
                if (_SceneSize == 0)
                {
                    return;
                }

                try
                {
                    _StartTime = Time.realtimeSinceStartup;

                    _FileContent = (byte *)UnsafeUtility.Malloc(_SceneSize, 16, Allocator.Persistent);

                    ReadCommand cmd;
                    cmd.Buffer  = _FileContent;
                    cmd.Offset  = 0;
                    cmd.Size    = _SceneSize;
                    _ReadHandle = AsyncReadManager.Read(_ScenePath, &cmd, 1);

                    if (_ExpectedObjectReferenceCount != 0)
                    {
#if UNITY_EDITOR
                        var resourceRequests = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(_ResourcesPathObjRefs);
                        _ResourceObjRefs = (ReferencedUnityObjects)resourceRequests[0];

                        _LoadingStatus = LoadingStatus.WaitingForResourcesLoad;
#else
                        _SceneBundleHandle = SceneBundleHandle.CreateOrRetainBundle(_ResourcesPathObjRefs);
                        _LoadingStatus     = LoadingStatus.WaitingForAssetBundleLoad;
#endif
                    }
                    else
                    {
                        _LoadingStatus = LoadingStatus.WaitingForEntitiesLoad;
                    }
                }
                catch (Exception e)
                {
                    _LoadingFailure = e.Message;
                    _LoadingStatus  = LoadingStatus.Completed;
                }
            }

            // Once async asset bundle load is done, we can read the asset
            if (_LoadingStatus == LoadingStatus.WaitingForAssetBundleLoad)
            {
                if (!_SceneBundleHandle.IsReady())
                {
                    return;
                }

                if (!_SceneBundleHandle.AssetBundle)
                {
                    _LoadingFailure = $"Failed to load Asset Bundle '{_ResourcesPathObjRefs}'";
                    _LoadingStatus  = LoadingStatus.Completed;
                    return;
                }

                var fileName = Path.GetFileName(_ResourcesPathObjRefs);

                _AssetRequest  = _SceneBundleHandle.AssetBundle.LoadAssetAsync(fileName);
                _LoadingStatus = LoadingStatus.WaitingForAssetLoad;
            }

            // Once async asset bundle load is done, we can read the asset
            if (_LoadingStatus == LoadingStatus.WaitingForAssetLoad)
            {
                if (!_AssetRequest.isDone)
                {
                    return;
                }

                if (!_AssetRequest.asset)
                {
                    _LoadingFailure = $"Failed to load Asset '{Path.GetFileName(_ResourcesPathObjRefs)}'";
                    _LoadingStatus  = LoadingStatus.Completed;
                    return;
                }

                _ResourceObjRefs = _AssetRequest.asset as ReferencedUnityObjects;

                if (_ResourceObjRefs == null)
                {
                    _LoadingFailure = $"Failed to load object references resource '{_ResourcesPathObjRefs}'";
                    _LoadingStatus  = LoadingStatus.Completed;
                    return;
                }

                _LoadingStatus = LoadingStatus.WaitingForEntitiesLoad;
            }

            // Once async resource load is done, we can async read the entity scene data
            if (_LoadingStatus == LoadingStatus.WaitingForResourcesLoad)
            {
                if (_ResourceObjRefs == null)
                {
                    _LoadingFailure = $"Failed to load object references resource '{_ResourcesPathObjRefs}'";
                    _LoadingStatus  = LoadingStatus.Completed;
                    return;
                }

                _LoadingStatus = LoadingStatus.WaitingForEntitiesLoad;
            }

            if (_LoadingStatus == LoadingStatus.WaitingForEntitiesLoad)
            {
                try
                {
                    _LoadingStatus = LoadingStatus.WaitingForSceneDeserialization;
                    ScheduleSceneRead(_ResourceObjRefs);

                    if (_BlockUntilFullyLoaded)
                    {
                        _EntityManager.ExclusiveEntityTransactionDependency.Complete();
                    }
                }
                catch (Exception e)
                {
                    _LoadingFailure = e.Message;
                    _LoadingStatus  = LoadingStatus.Completed;
                }
            }

            // Complete Loading status
            if (_LoadingStatus == LoadingStatus.WaitingForSceneDeserialization)
            {
                if (_EntityManager.ExclusiveEntityTransactionDependency.IsCompleted)
                {
                    _EntityManager.ExclusiveEntityTransactionDependency.Complete();

                    _LoadingStatus = LoadingStatus.Completed;
                    var currentTime = Time.realtimeSinceStartup;
                    var totalTime   = currentTime - _StartTime;
                    System.Console.WriteLine($"Streamed scene with {totalTime * 1000,3:f0}ms latency from {_ScenePath}");
                }
            }
        }
        protected override void OnUpdate()
        {
            var destroySubScenes = new NativeList <Entity>(Allocator.Temp);

            var sceneDataFromEntity = GetComponentDataFromEntity <SceneSectionData>();

            bool SceneSectionRequiresSynchronousLoading(Entity entity) =>
            (EntityManager.GetComponentData <RequestSceneLoaded>(entity).LoadFlags & SceneLoadFlags.BlockOnStreamIn) != 0;

            // Sections > 0 need the external references from sections 0 and will wait for it to be loaded.
            // So we have to ensure sections 0 are loaded first, otherwise there's a risk of starving loading streams.
            var priorityList = new NativeList <Entity>(Allocator.Temp);

            using (var entities = m_PendingStreamRequests.ToEntityArray(Allocator.TempJob))
            {
                var priorities = new NativeArray <int>(entities.Length, Allocator.Temp);

                for (int i = 0; i < entities.Length; ++i)
                {
                    var entity = entities[i];

                    if (SceneSectionRequiresSynchronousLoading(entity))
                    {
                        priorities[i] = 0;
                        var operation = CreateAsyncLoadSceneOperation(m_SynchronousSceneLoadWorld.EntityManager, entity, true);
                        var result    = UpdateLoadOperation(operation, m_SynchronousSceneLoadWorld, entity);

                        if (result == UpdateLoadOperationResult.Error)
                        {
                            m_SynchronousSceneLoadWorld.Dispose();
                            m_SynchronousSceneLoadWorld = new World("LoadingWorld (synchronous)");
                        }

                        Assert.AreNotEqual(UpdateLoadOperationResult.Aborted, result);
                    }
                    else if (sceneDataFromEntity[entity].SubSectionIndex == 0)
                    {
                        priorities[i] = 1;
                    }
                    else
                    {
                        priorities[i] = 2;
                    }
                }

                for (int priority = 1; priority <= 2; ++priority)
                {
                    for (int i = 0; i < entities.Length; ++i)
                    {
                        if (priorityList.Length == LoadScenesPerFrame)
                        {
                            break;
                        }

                        if (priorities[i] == priority)
                        {
                            priorityList.Add(entities[i]);
                        }
                    }
                }
            }

            var priorityArray = priorityList.AsArray();

            foreach (var entity in priorityArray)
            {
                var streamIndex = CreateAsyncLoadScene(entity, false);
                if (streamIndex != -1)
                {
                    var streamingState = new StreamingState {
                        ActiveStreamIndex = streamIndex, Status = StreamingStatus.NotYetProcessed
                    };
                    EntityManager.AddComponentData(entity, streamingState);
                }
            }

            Entities.With(m_UnloadStreamRequests).ForEach((Entity entity) =>
            {
                destroySubScenes.Add(entity);
            });

            foreach (var destroyScene in destroySubScenes.AsArray())
            {
                UnloadSectionImmediate(destroyScene);
            }

            if (ProcessActiveStreams())
            {
                EditorUpdateUtility.EditModeQueuePlayerLoopUpdate();
            }

            // Process unloading bundles
            SceneBundleHandle.ProcessUnloadingBundles();
        }
 public void Release()
 {
     _sceneBundleHandle?.Release();
     _sceneBundleHandle = null;
 }
 public SceneSectionBundle(SceneBundleHandle bundle)
 {
     _sceneBundleHandle = bundle;
 }