protected override unsafe void OnUpdate() { { var ecb = new EntityCommandBuffer(Allocator.Temp); Entities .WithAll <SceneData, RequestSceneLoaded>() .WithNone <SceneLoadRequest>() .ForEach((Entity e) => { if (m_currentRequestTotal >= kMaxRequestsInFlight) { return; } var sceneData = EntityManager.GetComponentData <SceneData>(e); var sceneGuid = sceneData.Scene.SceneGuid; var path = "Data/" + sceneGuid.Guid.ToString("N"); // Fire async reads for scene data SceneLoadRequest request = new SceneLoadRequest(); request.SceneOpHandle = IOService.RequestAsyncRead(path); ecb.AddComponent(e, request); ecb.RemoveComponent <RequestSceneLoaded>(e); sceneData.Status = SceneStatus.Loading; ecb.SetComponent(e, sceneData); m_currentRequestTotal++; }); ecb.Playback(EntityManager); ecb.Dispose(); } if (m_PendingRequestsQuery.CalculateLength() > 0) { var ecb = new EntityCommandBuffer(Allocator.Temp); var pendingRequests = m_PendingRequestsQuery.ToEntityArray(Allocator.Temp); Entity requestEntity = pendingRequests[0]; SceneData sceneData = EntityManager.GetComponentData <SceneData>(requestEntity); SceneLoadRequest request = EntityManager.GetComponentData <SceneLoadRequest>(requestEntity); var opStatus = request.SceneOpHandle.GetStatus(); if (opStatus <= Status.InProgress) { ecb.Playback(EntityManager); ecb.Dispose(); return; } if (opStatus == Status.Failure) { request.SceneOpHandle.Dispose(); ecb.RemoveComponent <SceneLoadRequest>(requestEntity); sceneData.Status = SceneStatus.FailedToLoad; ecb.SetComponent(requestEntity, sceneData); ecb.Playback(EntityManager); ecb.Dispose(); m_currentRequestTotal--; return; } Assert.IsTrue(opStatus == Status.Success); request.SceneOpHandle.GetData(out var data, out var sceneDataSize); SceneHeader header = *(SceneHeader *)data; int headerSize = UnsafeUtility.SizeOf <SceneHeader>(); if (header.Version != SceneHeader.CurrentVersion) { throw new Exception($"Scene serialization version mismatch. Reading version '{header.Version}', expected '{SceneHeader.CurrentVersion}'"); } byte *decompressedScene = data + headerSize; if (header.Codec != Codec.Codec.None) { decompressedScene = (byte *)UnsafeUtility.Malloc(header.DecompressedSize, 16, Allocator.Temp); if (!CodecService.Decompress(header.Codec, data + headerSize, sceneDataSize - headerSize, decompressedScene, header.DecompressedSize)) { throw new Exception($"Failed to decompress compressed scene using codec '{header.Codec}'"); } } using (var sceneReader = new MemoryBinaryReader(decompressedScene)) { var loadingEM = m_LoadingWorld.EntityManager; var transaction = loadingEM.BeginExclusiveEntityTransaction(); if (header.SharedComponentCount > 0) { int numSharedComponentsLoaded = SerializeUtility.DeserializeSharedComponents(loadingEM, sceneReader); // Chunks have now taken over ownership of the shared components (reference counts have been added) // so remove the ref that was added on deserialization for (int i = 0; i < numSharedComponentsLoaded; ++i) { transaction.ManagedComponentStore.RemoveReference(i + 1); } Assert.IsTrue(numSharedComponentsLoaded == header.SharedComponentCount, $"Number of loaded SharedComponents for '{sceneData.Scene.SceneGuid.Guid}' loaded ({numSharedComponentsLoaded }) does not match what we expect ({header.SharedComponentCount})"); } SerializeUtility.DeserializeWorld(transaction, sceneReader, header.SharedComponentCount); loadingEM.EndExclusiveEntityTransaction(); } var scene = sceneData.Scene; World.Active.EntityManager.MoveEntitiesFrom(out var movedEntities, m_LoadingWorld.EntityManager); foreach (var e in movedEntities) { World.Active.EntityManager.AddSharedComponentData(e, scene.SceneGuid); World.Active.EntityManager.AddSharedComponentData(e, scene.SceneInstanceId); } // Fixup Entity references now that the entities have moved EntityManager.World.GetOrCreateSystem <EntityReferenceRemapSystem>().Update(); EntityManager.World.GetOrCreateSystem <RemoveRemapInformationSystem>().Update(); if (header.Codec != Codec.Codec.None) { UnsafeUtility.Free(decompressedScene, Allocator.Temp); } sceneData.Status = SceneStatus.Loaded; ecb.SetComponent(requestEntity, sceneData); ecb.AddSharedComponent(requestEntity, scene.SceneGuid); ecb.AddSharedComponent(requestEntity, scene.SceneInstanceId); request.SceneOpHandle.Dispose(); ecb.RemoveComponent <SceneLoadRequest>(requestEntity); ecb.Playback(EntityManager); ecb.Dispose(); m_LoadingWorld.EntityManager.PrepareForDeserialize(); movedEntities.Dispose(); pendingRequests.Dispose(); m_currentRequestTotal--; } }
protected override unsafe void OnUpdate() { var ecb = new EntityCommandBuffer(Allocator.TempJob); Entities .WithAll <SceneData, RequestSceneLoaded>() .WithNone <SceneLoadRequest>() .ForEach((Entity e) => { var sceneData = EntityManager.GetComponentData <SceneData>(e); var sceneGuid = sceneData.Scene.SceneGuid; var path = DataRootPath + sceneGuid.Guid.ToString("N"); #if IO_ENABLE_TRACE Debug.Log($"SceneStreamingSystem: starting load for {DebugSceneGuid(sceneData)} from {path}"); #endif // Fire async reads for scene data SceneLoadRequest request = new SceneLoadRequest(); request.SceneOpHandle = IOService.RequestAsyncRead(path); ecb.AddComponent(e, request); ecb.RemoveComponent <RequestSceneLoaded>(e); sceneData.Status = SceneStatus.Loading; ecb.SetComponent(e, sceneData); }); ecb.Playback(EntityManager); ecb.Dispose(); var pendingRequests = m_PendingRequestsQuery.ToEntityArray(Allocator.TempJob); ecb = new EntityCommandBuffer(Allocator.TempJob); foreach (var requestEntity in pendingRequests) { SceneData sceneData = EntityManager.GetComponentData <SceneData>(requestEntity); SceneLoadRequest request = EntityManager.GetComponentData <SceneLoadRequest>(requestEntity); var opStatus = request.SceneOpHandle.GetStatus(); if (opStatus <= Status.InProgress) { continue; } if (opStatus == Status.Failure) { request.SceneOpHandle.Dispose(); ecb.RemoveComponent <SceneLoadRequest>(requestEntity); Debug.Log($"SceneStreamingSystem: Failed to load {DebugSceneGuid(sceneData)}"); sceneData.Status = SceneStatus.FailedToLoad; ecb.SetComponent(requestEntity, sceneData); continue; } Assert.IsTrue(opStatus == Status.Success); request.SceneOpHandle.GetData(out var data, out var sceneDataSize); SceneHeader header = *(SceneHeader *)data; int headerSize = UnsafeUtility.SizeOf <SceneHeader>(); if (header.Version != SceneHeader.CurrentVersion) { throw new Exception($"Scene serialization version mismatch in {DebugSceneGuid(sceneData)}. Reading version '{header.Version}', expected '{SceneHeader.CurrentVersion}'"); } byte *decompressedScene = data + headerSize; if (header.Codec != Codec.Codec.None) { decompressedScene = (byte *)UnsafeUtility.Malloc(header.DecompressedSize, 16, Allocator.Temp); if (!CodecService.Decompress(header.Codec, data + headerSize, sceneDataSize - headerSize, decompressedScene, header.DecompressedSize)) { throw new Exception($"Failed to decompress compressed scene {DebugSceneGuid(sceneData)} using codec '{header.Codec}'"); } } using (var sceneReader = new MemoryBinaryReader(decompressedScene)) { var loadingEM = m_LoadingWorld.EntityManager; var transaction = loadingEM.BeginExclusiveEntityTransaction(); SerializeUtility.DeserializeWorld(transaction, sceneReader); loadingEM.EndExclusiveEntityTransaction(); } var scene = sceneData.Scene; var activeEM = EntityManager; activeEM.MoveEntitiesFrom(out var movedEntities, m_LoadingWorld.EntityManager); foreach (var e in movedEntities) { ecb.AddSharedComponent(e, scene.SceneGuid); ecb.AddSharedComponent(e, scene.SceneInstanceId); } // Fixup Entity references now that the entities have moved EntityManager.World.GetExistingSystem <EntityReferenceRemapSystem>().Update(); EntityManager.World.GetExistingSystem <RemoveRemapInformationSystem>().Update(); if (header.Codec != Codec.Codec.None) { UnsafeUtility.Free(decompressedScene, Allocator.Temp); } #if IO_ENABLE_TRACE Debug.Log($"SceneStreamingSystem: Loaded scene {DebugSceneGuid(sceneData)}"); #endif sceneData.Status = SceneStatus.Loaded; ecb.SetComponent(requestEntity, sceneData); request.SceneOpHandle.Dispose(); ecb.RemoveComponent <SceneLoadRequest>(requestEntity); m_LoadingWorld.EntityManager.PrepareForDeserialize(); movedEntities.Dispose(); } ecb.Playback(EntityManager); ecb.Dispose(); pendingRequests.Dispose(); }