void OnValidate() { _SceneGUID = new GUID(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_SceneAsset))); if (_IsAddedToListOfAllSubScenes && IsInMainStage()) { if (_SceneGUID != _AddedSceneGUID) { RemoveSceneEntities(); if (_SceneGUID != default) { AddSceneEntities(); } } } // Validate SubScene build configuration exists foreach (var world in World.AllWorlds) { var sceneSystem = world.GetExistingSystem <SceneSystem>(); if (sceneSystem is null) { continue; } EntityScenesPaths.CreateBuildConfigurationSceneFile(_SceneGUID, sceneSystem.BuildConfigurationGUID); } }
static void CreatePlayerLiveLinkCacheDir() { if (!Directory.Exists(EntityScenesPaths.GetLiveLinkCacheDirPath())) { Directory.CreateDirectory(EntityScenesPaths.GetLiveLinkCacheDirPath()); } }
void ResolveScene(Entity sceneEntity, ref SceneReference scene, RequestSceneLoaded requestSceneLoaded, Hash128 artifactHash) { // Resolve first (Even if the file doesn't exist we want to stop continously trying to load the section) EntityManager.AddBuffer <ResolvedSectionEntity>(sceneEntity); EntityManager.AddComponentData(sceneEntity, new ResolvedSceneHash { ArtifactHash = artifactHash }); var sceneHeaderPath = EntityScenesPaths.GetLiveLinkCachePath(artifactHash, EntityScenesPaths.PathType.EntitiesHeader, -1); if (!File.Exists(sceneHeaderPath)) { Debug.LogError($"Loading Entity Scene failed because the entity header file could not be found: {scene.SceneGUID}\n{sceneHeaderPath}"); return; } if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + scene.SceneGUID); return; } LogResolving("ResolveScene (success)", scene.SceneGUID); ref var sceneMetaData = ref sceneMetaDataRef.Value;
internal static List <SceneBundleHandle> LoadSceneBundles(string mainBundlePath, NativeArray <Entities.Hash128> sharedBundles, bool blocking) { var bundles = new List <SceneBundleHandle>(); if (sharedBundles.IsCreated) { for (int i = 0; i < sharedBundles.Length; i++) { var path = $"{Application.streamingAssetsPath}/{EntityScenesPaths.RelativePathFolderFor(sharedBundles[i], EntityScenesPaths.PathType.EntitiesSharedReferencesBundle, -1)}"; bundles.Add(CreateOrRetainBundle(path)); } sharedBundles.Dispose(); } if (!string.IsNullOrEmpty(mainBundlePath)) { bundles.Insert(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); }
unsafe void ReceiveAssetTargetHash(MessageEventArgs args) { using (var resolvedAssets = args.ReceiveArray <ResolvedAssetID>()) { foreach (var asset in resolvedAssets) { if (!asset.TargetHash.IsValid) { // If hash is invalid, then it means we should be waiting on it, but the hash will come later when it finishes importing on the editor LiveLinkMsg.LogReceived($"ReceiveAssetTargetHash => {asset.GUID} | {asset.TargetHash}, Invalid Hash (Still waiting)"); m_WaitingForAssets[asset.GUID] = new Hash128(); } else { //TODO: Should we compare against already loaded assets here? if (File.Exists(EntityScenesPaths.GetCachePath(asset.TargetHash))) { LiveLinkMsg.LogReceived($"ReceiveAssetTargetHash => {asset.GUID} | {asset.TargetHash}, File.Exists => 'True'"); m_WaitingForAssets[asset.GUID] = asset.TargetHash; } else { LiveLinkMsg.LogReceived($"ReceiveAssetTargetHash => {asset.GUID} | {asset.TargetHash}, File.Exists => 'False'"); m_WaitingForAssets[asset.GUID] = new Hash128(); LiveLinkMsg.LogSend($"AssetBundleBuild request '{asset.GUID}'"); m_Connection.Send(LiveLinkMsg.PlayerRequestAssetForGUID, asset.GUID); } } } } }
void ResolveScene(Entity sceneEntity, ref SceneReference scene, RequestSceneLoaded requestSceneLoaded, Hash128 artifactHash) { // Resolve first (Even if the file doesn't exist we want to stop continously trying to load the section) EntityManager.AddBuffer <ResolvedSectionEntity>(sceneEntity); #if UNITY_EDITOR && !USE_SUBSCENE_EDITORBUNDLES EntityManager.AddComponentData(sceneEntity, new ResolvedSceneHash { ArtifactHash = artifactHash }); UnityEditor.Experimental.AssetDatabaseExperimental.GetArtifactPaths(artifactHash, out var paths); var sceneHeaderPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesHeader); #else var sceneHeaderPath = EntityScenesPaths.GetLoadPath(scene.SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); #endif if (!File.Exists(sceneHeaderPath)) { Debug.LogError($"Loading Entity Scene failed because the entity header file could not be found: {scene.SceneGUID}\n{sceneHeaderPath}"); return; } if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + scene.SceneGUID); return; } LogResolving("ResolveScene (success)", scene.SceneGUID); ref var sceneMetaData = ref sceneMetaDataRef.Value;
void UpdateSceneContentsChanged(Hash128 buildSettingGUID) { #if UNITY_EDITOR Entities.With(m_ResolvedScenes).ForEach((Entity sceneEntity, ref SceneReference scene, ref ResolvedSceneHash resolvedScene) => { LogResolving("Queuing UpdateSceneContentsChanged", scene.SceneGUID); var hash = EntityScenesPaths.GetSubSceneArtifactHash(scene.SceneGUID, buildSettingGUID, UnityEditor.Experimental.AssetDatabaseExperimental.ImportSyncMode.Queue); if ((hash != default) && (hash != resolvedScene.ArtifactHash)) { NotifySceneContentsHasChanged(scene.SceneGUID); } }); #endif if (m_ChangedScenes.Length != 0) { var sceneSystem = World.GetExistingSystem <SceneSystem>(); foreach (var scene in m_ChangedScenes) { var sceneEntity = sceneSystem.GetSceneEntity(scene); // Don't touch it if the scene is under live link control (@Todo: SubSceneStreamingSystem.IgnoreTag could be live link specific?) if (sceneEntity != Entity.Null && !EntityManager.HasComponent <DisableSceneResolveAndLoad>(sceneEntity)) { var unloadFlags = SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded; sceneSystem.UnloadScene(sceneEntity, unloadFlags); } } m_ChangedScenes.Clear(); } }
void ResolveScene(Entity sceneEntity, ref SceneReference scene, RequestSceneLoaded requestSceneLoaded, Hash128 artifactHash) { // Resolve first (Even if the file doesn't exist we want to stop continously trying to load the section) EntityManager.AddBuffer <ResolvedSectionEntity>(sceneEntity); #if UNITY_EDITOR && !USE_SUBSCENE_EDITORBUNDLES EntityManager.AddComponentData(sceneEntity, new ResolvedSceneHash { ArtifactHash = artifactHash }); UnityEditor.Experimental.AssetDatabaseExperimental.GetArtifactPaths(artifactHash, out var paths); var sceneHeaderPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesHeader); #else var sceneHeaderPath = EntityScenesPaths.GetLoadPath(scene.SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); #endif #if UNITY_ANDROID && !UNITY_EDITOR var uwrFile = new UnityWebRequest(sceneHeaderPath); uwrFile.downloadHandler = new DownloadHandlerBuffer(); uwrFile.SendWebRequest(); while (!uwrFile.isDone) { } if (uwrFile.isNetworkError || uwrFile.isHttpError) { Debug.LogError($"Loading Entity Scene failed because the entity header file could not be found: {scene.SceneGUID}\nNOTE: In order to load SubScenes in the player you have to use the new BuildSettings asset based workflow to build & run your player.\n{sceneHeaderPath}"); return; } if (!BlobAssetReference <SceneMetaData> .TryRead(uwrFile.downloadHandler.data, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + scene.SceneGUID); return; } #else if (!File.Exists(sceneHeaderPath)) { #if UNITY_EDITOR Debug.LogError($"Loading Entity Scene failed because the entity header file could not be found: {scene.SceneGUID}\n{sceneHeaderPath}"); #else Debug.LogError($"Loading Entity Scene failed because the entity header file could not be found: {scene.SceneGUID}\nNOTE: In order to load SubScenes in the player you have to use the new BuildSettings asset based workflow to build & run your player.\n{sceneHeaderPath}"); #endif return; } if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + scene.SceneGUID); return; } #endif LogResolving("ResolveScene (success)", scene.SceneGUID); ref var sceneMetaData = ref sceneMetaDataRef.Value;
//TODO: There is too much code duplication here, refactor this to receive general artifacts from the editor unsafe void ReceiveSubSceneRefGUIDs(MessageEventArgs args) { fixed(byte *ptr = args.data) { var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length); var subSceneAsset = reader.ReadNext <ResolvedSubSceneID>(); var sectionIndex = reader.ReadNext <int>(); reader.ReadNext(out NativeArray <RuntimeGlobalObjectId> objRefGUIDs, Allocator.Persistent); var refObjGUIDsPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesUnityObjectReferences, sectionIndex); // Not printing error because this can happen when running the same player multiple times on the same machine if (File.Exists(refObjGUIDsPath)) { LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} but it already exists on disk"); } else { LiveLinkMsg.LogInfo($"ReceieveSubSceneRefGUIDs => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash},"); var tempCachePath = GetTempCachePath(); using (var writer = new StreamBinaryWriter(tempCachePath)) { writer.Write(objRefGUIDs.Length); writer.WriteArray(objRefGUIDs); } try { File.Move(tempCachePath, refObjGUIDsPath); } catch (Exception e) { File.Delete(tempCachePath); if (!File.Exists(refObjGUIDsPath)) { Debug.LogError($"Failed to move temporary file. Exception: {e.Message}"); LiveLinkMsg.LogInfo($"Failed to move temporary file. Exception: {e.Message}"); } } } if (!_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID)) { Debug.LogError($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it"); LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it"); return; } var waitingSubScene = _WaitingForSubScenes[subSceneAsset.SubSceneGUID]; waitingSubScene.SubSections.Add(objRefGUIDs); _WaitingForSubScenes[subSceneAsset.SubSceneGUID] = waitingSubScene; } }
public static unsafe void WritePlayerLiveLinkCacheGUID() { CreatePlayerLiveLinkCacheDir(); var cacheGUIDPath = $"{EntityScenesPaths.GetLiveLinkCacheDirPath()}/livelinkcacheguid"; using (var stream = new StreamBinaryWriter(cacheGUIDPath)) { Hash128 guid = LiveLinkCacheGUID; stream.WriteBytes(&guid, sizeof(Hash128)); } }
unsafe void ReceiveResponseSubSceneTargetHash(MessageEventArgs args) { using (var subSceneAssets = args.ReceiveArray <ResolvedSubSceneID>()) { foreach (var subSceneAsset in subSceneAssets) { if (_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID)) { return; } var headerPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesHeader, -1); if (File.Exists(headerPath)) { LiveLinkMsg.LogInfo($"ReceiveResponseSubSceneTargetHash => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, File.Exists => 'True', {Path.GetFullPath(headerPath)}"); //TODO: This is a hack to make sure assets are managed by asset manifest when loading from cache for first run if (!BlobAssetReference <SceneMetaData> .TryRead(headerPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + subSceneAsset.SubSceneGUID); return; } ref var sceneMetaData = ref sceneMetaDataRef.Value; var waitingSubScene = new WaitingSubScene { TargetHash = subSceneAsset.TargetHash, SubSections = new List <NativeArray <RuntimeGlobalObjectId> >(), SubSectionCount = sceneMetaData.Sections.Length }; for (int i = 0; i < sceneMetaData.Sections.Length; i++) { if (sceneMetaData.Sections[i].ObjectReferenceCount != 0) { var refObjGUIDsPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesUnityObjectReferences, i); using (var reader = new StreamBinaryReader(refObjGUIDsPath)) { var numObjRefGUIDs = reader.ReadInt(); NativeArray <RuntimeGlobalObjectId> objRefGUIDs = new NativeArray <RuntimeGlobalObjectId>(numObjRefGUIDs, Allocator.Persistent); reader.ReadArray(objRefGUIDs, numObjRefGUIDs); waitingSubScene.SubSections.Add(objRefGUIDs); } } else { waitingSubScene.SubSections.Add(new NativeArray <RuntimeGlobalObjectId>(0, Allocator.Persistent)); } } _WaitingForSubScenes[subSceneAsset.SubSceneGUID] = waitingSubScene; }
unsafe void ReceiveSubSceneHeader(MessageEventArgs args) { fixed(byte *ptr = args.data) { var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length); var subSceneAsset = reader.ReadNext <ResolvedSubSceneID>(); var subSectionCount = reader.ReadNext <int>(); var headerPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesHeader, -1); // Not printing error because this can happen when running the same player multiple times on the same machine if (File.Exists(headerPath)) { LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} but it already exists on disk"); } else { var tempCachePath = GetTempCachePath(); LiveLinkMsg.LogInfo($"ReceiveSubSceneHeader => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, '{tempCachePath}' => '{headerPath}'"); var stream = File.OpenWrite(tempCachePath); stream.Write(args.data, reader.Offset, args.data.Length - reader.Offset); stream.Close(); stream.Dispose(); try { File.Move(tempCachePath, headerPath); } catch (Exception e) { File.Delete(tempCachePath); if (!File.Exists(headerPath)) { Debug.LogError($"Failed to move temporary file. Exception: {e.Message}"); LiveLinkMsg.LogInfo($"Failed to move temporary file. Exception: {e.Message}"); } } } if (!_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID)) { Debug.LogError($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it"); LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it"); return; } var waitingSubScene = _WaitingForSubScenes[subSceneAsset.SubSceneGUID]; waitingSubScene.TargetHash = subSceneAsset.TargetHash; waitingSubScene.SubSectionCount = subSectionCount; _WaitingForSubScenes[subSceneAsset.SubSceneGUID] = waitingSubScene; } }
public static unsafe void ReadPlayerLiveLinkCacheGUID() { var cacheGUIDPath = $"{EntityScenesPaths.GetLiveLinkCacheDirPath()}/livelinkcacheguid"; if (File.Exists(cacheGUIDPath)) { using (var rdr = new StreamBinaryReader(cacheGUIDPath)) { Hash128 guid = default; rdr.ReadBytes(&guid, sizeof(Hash128)); LiveLinkCacheGUID = guid; } } }
//@TODO: Support some sort of transaction like API so we can reload all changed things in batch. unsafe void ReceiveAsset(MessageEventArgs args) { LiveLinkMsg.LogReceived($"AssetBundle: '{args.data.Length}' bytes"); fixed(byte *ptr = args.data) { var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length); var asset = reader.ReadNext <ResolvedAssetID>(); var assetBundleCachePath = EntityScenesPaths.GetCachePath(asset.TargetHash); // Not printing error because this can happen when running the same player multiple times on the same machine if (File.Exists(assetBundleCachePath)) { LiveLinkMsg.LogInfo($"Received {asset.GUID} | {asset.TargetHash} but it already exists on disk"); } else { // cache: look up asset by target hash to see if the version we want is already on the target device //if we already have the asset bundle revision we want, then just put that in the resolver as the active revision of the asset // cache: if not in cache, write actual file to Application.persistentDatapath var tempCachePath = EntityScenesPaths.GetTempCachePath(); LiveLinkMsg.LogInfo($"ReceiveAssetBundle => {asset.GUID} | {asset.TargetHash}, '{tempCachePath}' => '{assetBundleCachePath}'"); using (var stream = File.OpenWrite(tempCachePath)) stream.Write(args.data, reader.Offset, args.data.Length - reader.Offset); try { File.Move(tempCachePath, assetBundleCachePath); } catch (Exception e) { File.Delete(tempCachePath); if (!File.Exists(assetBundleCachePath)) { Debug.LogError($"Failed to move temporary file. Source: {tempCachePath} | Destination: {assetBundleCachePath} - Exception: {e.Message}"); LiveLinkMsg.LogInfo($"Failed to move temporary file. Exception: {e.Message}"); } } } if (!m_WaitingForAssets.ContainsKey(asset.GUID)) { LiveLinkMsg.LogInfo($"Received {asset.GUID} | {asset.TargetHash} without requesting it"); } m_WaitingForAssets[asset.GUID] = asset.TargetHash; } }
public static void ClearPlayerLiveLinkCache() { var cachePath = EntityScenesPaths.GetLiveLinkCacheDirPath(); if (Directory.Exists(cachePath)) { try { Directory.Delete(cachePath, true); } catch (SystemException exception) { Debug.LogError($"Failed to delete LiveLink cache! {exception.Message}"); } } }
public void UpdateSceneEntities() { #if UNITY_EDITOR var sceneHeaderPath = EntityScenesPaths.GetLoadPath(SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); m_SubSceneHeader = AssetDatabase.LoadAssetAtPath <SubSceneHeader>(sceneHeaderPath); #endif if (_SceneEntityManager != null && _SceneEntityManager.IsCreated) { foreach (var sceneEntity in _SceneEntities) { _SceneEntityManager.DestroyEntity(sceneEntity); } } _SceneEntities.Clear(); _SceneEntityManager = null; DefaultWorldInitialization.DefaultLazyEditModeInitialize(); if (World.Active != null && m_SubSceneHeader != null) { _SceneEntityManager = World.Active.EntityManager; for (int i = 0; i < m_SubSceneHeader.Sections.Length; ++i) { var sceneEntity = _SceneEntityManager.CreateEntity(); #if UNITY_EDITOR _SceneEntityManager.SetName(sceneEntity, i == 0 ? $"Scene: {SceneName}" : $"Scene: {SceneName} ({i})"); #endif _SceneEntities.Add(sceneEntity); _SceneEntityManager.AddComponentObject(sceneEntity, this); if (AutoLoadScene) { _SceneEntityManager.AddComponentData(sceneEntity, new RequestSceneLoaded()); } _SceneEntityManager.AddComponentData(sceneEntity, m_SubSceneHeader.Sections[i]); _SceneEntityManager.AddComponentData(sceneEntity, new SceneBoundingVolume { Value = m_SubSceneHeader.Sections[i].BoundingVolume }); } } }
unsafe void ReceiveBuildArtifact(MessageEventArgs args) { fixed(byte *ptr = args.data) { LiveLinkMsg.LogInfo($"ReceiveBuildArtifact => Buffer Size: {args.data.Length}"); var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length); reader.ReadNext(out string artifactFileName); string artifactPath = EntityScenesPaths.ComposeLiveLinkCachePath(artifactFileName); if (!File.Exists(artifactPath)) { LiveLinkMsg.LogInfo($"ReceiveBuildArtifact => {artifactPath}"); var tempCachePath = GetTempCachePath(); try { var stream = File.OpenWrite(tempCachePath); stream.Write(args.data, reader.Offset, args.data.Length - reader.Offset); stream.Close(); stream.Dispose(); File.Move(tempCachePath, artifactPath); LiveLinkMsg.LogInfo($"ReceiveBuildArtifact => Successfully written to disc."); } catch (Exception e) { if (File.Exists(tempCachePath)) { File.Delete(tempCachePath); } if (!File.Exists(artifactPath)) { Debug.LogError($"Failed to move temporary file. Exception: {e.Message}"); } } } } }
int CreateAsyncLoadScene(Entity entity) { for (int i = 0; i != m_Streams.Length; i++) { if (m_Streams[i].Operation != null) { continue; } var sceneData = EntityManager.GetComponentData <SceneData>(entity); var entitiesBinaryPath = EntityScenesPaths.GetLoadPath(sceneData.SceneGUID, EntityScenesPaths.PathType.EntitiesBinary, sceneData.SubSectionIndex); var resourcesPath = EntityScenesPaths.GetLoadPath(sceneData.SceneGUID, EntityScenesPaths.PathType.EntitiesSharedComponents, sceneData.SubSectionIndex); var entityManager = m_Streams[i].World.GetOrCreateManager <EntityManager>(); m_Streams[i].Operation = new AsyncLoadSceneOperation(entitiesBinaryPath, sceneData.FileSize, sceneData.SharedComponentCount, resourcesPath, entityManager); m_Streams[i].SceneEntity = entity; return(i); } return(-1); }
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 void RequestLoadAndPollSceneMetaData(EntityManager EntityManager, Entity sceneEntity, Hash128 sceneGUID) { var sceneHeaderPath = EntityScenesPaths.GetLoadPath(sceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); RequestSceneHeader requestSceneHeader; if (!EntityManager.HasComponent <RequestSceneHeader>(sceneEntity)) { requestSceneHeader.IOHandle = IOService.RequestAsyncRead(sceneHeaderPath).m_Handle; EntityManager.AddComponentData(sceneEntity, requestSceneHeader); } else { requestSceneHeader = EntityManager.GetComponentData <RequestSceneHeader>(sceneEntity); } var asyncOp = new AsyncOp() { m_Handle = requestSceneHeader.IOHandle }; var sceneHeaderStatus = asyncOp.GetStatus(); if (sceneHeaderStatus <= AsyncOp.Status.InProgress) { return; } if (sceneHeaderStatus != AsyncOp.Status.Success) { Debug.LogError($"Loading Entity Scene failed because the entity header file could not be read: guid={sceneGUID}."); } // Even if the file doesn't exist we want to stop continously trying to load the scene metadata EntityManager.AddComponentData(sceneEntity, new SceneMetaDataLoaded() { Success = sceneHeaderStatus == AsyncOp.Status.Success }); }
void OnEnable() { #if UNITY_EDITOR if (UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage(gameObject) != null) { return; } m_SubSceneHeader = null; if (SceneAsset == null) { return; } foreach (var subscene in m_AllSubScenes) { if (subscene.SceneAsset == SceneAsset) { Debug.LogWarning($"A sub-scene can not include the same scene ('{EditableScenePath}') multiple times.", this); return; } } m_AllSubScenes.Add(this); var sceneHeaderPath = EntityScenesPaths.GetLoadPath(SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); m_SubSceneHeader = AssetDatabase.LoadAssetAtPath <SubSceneHeader>(sceneHeaderPath); if (m_SubSceneHeader == null) { Debug.LogWarning($"Sub-scene '{EditableScenePath}' has no valid header at '{sceneHeaderPath}'. Please rebuild the Entity Cache.", this); return; } #endif UpdateSceneEntities(); }
public static bool ResolveSceneSections(EntityManager EntityManager, Entity sceneEntity, Hash128 sceneGUID, RequestSceneLoaded requestSceneLoaded, Hash128 artifactHash) { // Resolve first (Even if the file doesn't exist we want to stop continously trying to load the section) EntityManager.AddBuffer <ResolvedSectionEntity>(sceneEntity); #if UNITY_EDITOR && !USE_SUBSCENE_EDITORBUNDLES EntityManager.AddComponentData(sceneEntity, new ResolvedSceneHash { ArtifactHash = artifactHash }); AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var paths); var sceneHeaderPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesHeader); #else var sceneHeaderPath = EntityScenesPaths.GetLoadPath(sceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); #endif // @TODO: AsyncReadManager currently crashes with empty path. // It should be possible to remove this after that is fixed. if (String.IsNullOrEmpty(sceneHeaderPath)) { Debug.LogError($"Loading Entity Scene failed because the entity header file couldn't be resolved: guid={sceneGUID}."); return(false); } if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { #if UNITY_EDITOR Debug.LogError($"Loading Entity Scene failed because the entity header file was an old version or doesn't exist: guid={sceneGUID} path={sceneHeaderPath}"); #else Debug.LogError($"Loading Entity Scene failed because the entity header file was an old version or doesn't exist: {sceneGUID}\nNOTE: In order to load SubScenes in the player you have to use the new BuildConfiguration asset based workflow to build & run your player.\n{sceneHeaderPath}"); #endif return(false); } ref var sceneMetaData = ref sceneMetaDataRef.Value;
void LoadAssetBundles(NativeArray <ResolvedAssetID> assets) { LiveLinkMsg.LogInfo("--- Begin Load asset bundles"); var patchAssetBundles = new List <AssetBundle>(); var patchAssetBundlesPath = new List <string>(); var newAssetBundles = new List <Hash128>(); var assetBundleToValidate = new List <Hash128>(); foreach (var asset in assets) { var assetGUID = asset.GUID; var targetHash = asset.TargetHash; var assetBundleCachePath = EntityScenesPaths.GetCachePath(targetHash); //if we already loaded an asset bundle and we just need a refresh var oldAssetBundle = globalAssetObjectResolver.GetAssetBundle(assetGUID); if (oldAssetBundle != null) { if (oldAssetBundle.isStreamedSceneAssetBundle) { LiveLinkMsg.LogInfo($"Unloading scene bundle: {assetGUID}"); var sceneSystem = World.GetExistingSystem <SceneSystem>(); sceneSystem.UnloadScene(assetGUID); globalAssetObjectResolver.UnloadAsset(assetGUID); continue; } else { LiveLinkMsg.LogInfo($"patching asset bundle: {assetGUID}"); patchAssetBundles.Add(oldAssetBundle); patchAssetBundlesPath.Add(assetBundleCachePath); globalAssetObjectResolver.UpdateTargetHash(assetGUID, targetHash); newAssetBundles.Add(assetGUID); } } else { LiveLinkMsg.LogInfo($"Loaded asset bundle: {assetGUID}"); var loadedAssetBundle = AssetBundle.LoadFromFile(assetBundleCachePath); globalAssetObjectResolver.AddAsset(assetGUID, targetHash, null, loadedAssetBundle); newAssetBundles.Add(assetGUID); } assetBundleToValidate.Add(assetGUID); //@TODO: Keep a hashtable of guid -> entity? Entities.ForEach((Entity entity, ref ResourceGUID guid) => { if (guid.Guid == assetGUID) { EntityManager.AddComponentData(entity, new ResourceLoaded()); } }); } AssetBundleUtility.PatchAssetBundles(patchAssetBundles.ToArray(), patchAssetBundlesPath.ToArray()); foreach (var assetGUID in newAssetBundles) { var assetBundle = globalAssetObjectResolver.GetAssetBundle(assetGUID); if (assetBundle == null) { Debug.LogError($"Could not load requested asset bundle.'"); return; } if (!assetBundle.isStreamedSceneAssetBundle) { var loadedManifest = assetBundle.LoadAsset <AssetObjectManifest>(assetGUID.ToString()); if (loadedManifest == null) { Debug.LogError($"Loaded {assetGUID} failed to load ObjectManifest"); return; } globalAssetObjectResolver.UpdateObjectManifest(assetGUID, loadedManifest); } } foreach (var assetGUID in assetBundleToValidate) { globalAssetObjectResolver.Validate(assetGUID); } LiveLinkMsg.LogInfo("--- End Load asset bundles"); }
//@TODO: What happens if we change source assets between queuing a request for the first time and it being resolved? protected override void OnUpdate() { //TODO: How can we disable systems in specific builds? #if !UNITY_EDITOR Enabled = !LiveLinkUtility.LiveLinkEnabled; if (!Enabled) { return; } #else SceneWithBuildConfigurationGUIDs.ValidateBuildSettingsCache(); #endif var buildConfigurationGUID = World.GetExistingSystem <SceneSystem>().BuildConfigurationGUID; UpdateSceneContentsChanged(buildConfigurationGUID); #if UNITY_EDITOR && !USE_SUBSCENE_EDITORBUNDLES Entities.With(m_ImportingScenes).ForEach((Entity sceneEntity, ref SceneReference scene, ref RequestSceneLoaded requestSceneLoaded) => { var hash = EntityScenesPaths.GetSubSceneArtifactHash(scene.SceneGUID, buildConfigurationGUID, ImportMode.NoImport); if (hash.IsValid) { LogResolving("Polling Importing (completed)", scene.SceneGUID); ResolveScene(sceneEntity, ref scene, requestSceneLoaded, hash); } else { LogResolving("Polling Importing (not complete)", scene.SceneGUID); } }); #endif //@TODO: Temporary workaround to prevent crash after build player if (m_ScenesToRequest.IsEmptyIgnoreFilter) { return; } // We are seeing this scene for the first time, so we need to schedule a request. Entities.With(m_ScenesToRequest).ForEach((Entity sceneEntity, ref SceneReference scene, ref RequestSceneLoaded requestSceneLoaded) => { #if UNITY_EDITOR && !USE_SUBSCENE_EDITORBUNDLES var blocking = (requestSceneLoaded.LoadFlags & SceneLoadFlags.BlockOnImport) != 0; var importMode = blocking ? ImportMode.Synchronous : ImportMode.Asynchronous; var hash = EntityScenesPaths.GetSubSceneArtifactHash(scene.SceneGUID, buildConfigurationGUID, importMode); if (hash.IsValid) { LogResolving(blocking ? "Blocking import (completed)" : "Queue not yet requested (completed)", scene.SceneGUID); ResolveScene(sceneEntity, ref scene, requestSceneLoaded, hash); } else { LogResolving(blocking ? "Blocking import (failed)" : "Queue not yet requested (not complete)", scene.SceneGUID); } #else ResolveScene(sceneEntity, ref scene, requestSceneLoaded, new Hash128()); #endif }); EntityManager.AddComponent(m_ScenesToRequest, ComponentType.ReadWrite <ResolvedSectionEntity>()); }
public void UpdateSceneEntities(bool warnIfMissing = false) { #if UNITY_EDITOR var sceneHeaderPath = EntityScenesPaths.GetLoadPath(SceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); m_SubSceneHeader = AssetDatabase.LoadAssetAtPath <SubSceneHeader>(sceneHeaderPath); #endif if (warnIfMissing && m_SubSceneHeader == null) { #if UNITY_EDITOR Debug.LogWarning($"Sub-scene '{EditableScenePath}' has no valid header at '{sceneHeaderPath}'. Please rebuild the Entity Cache.", this); #else Debug.LogWarning($"Sub-scene '{name}' has no valid header. Please rebuild the Entity Cache.", this); #endif } if (_SceneEntityManager != null && _SceneEntityManager.IsCreated) { foreach (var sceneEntity in _SceneEntities) { _SceneEntityManager.DestroyEntity(sceneEntity); } } _SceneEntities.Clear(); _SceneEntityManager = null; DefaultWorldInitialization.DefaultLazyEditModeInitialize(); if (World.Active != null) { _SceneEntityManager = World.Active.EntityManager; if (m_SubSceneHeader != null) { for (int i = 0; i < m_SubSceneHeader.Sections.Length; ++i) { var sceneEntity = _SceneEntityManager.CreateEntity(); #if UNITY_EDITOR _SceneEntityManager.SetName(sceneEntity, i == 0 ? $"Scene: {SceneName}" : $"Scene: {SceneName} ({i})"); #endif _SceneEntities.Add(sceneEntity); _SceneEntityManager.AddComponentObject(sceneEntity, this); if (AutoLoadScene) { _SceneEntityManager.AddComponentData(sceneEntity, new RequestSceneLoaded()); } _SceneEntityManager.AddComponentData(sceneEntity, m_SubSceneHeader.Sections[i]); _SceneEntityManager.AddComponentData(sceneEntity, new SceneBoundingVolume { Value = m_SubSceneHeader.Sections[i].BoundingVolume }); } } else { var sceneEntity = _SceneEntityManager.CreateEntity(); #if UNITY_EDITOR _SceneEntityManager.SetName(sceneEntity, "Scene: {SceneName}"); #endif _SceneEntities.Add(sceneEntity); _SceneEntityManager.AddComponentObject(sceneEntity, this); } } }
public unsafe static bool ResolveSceneSections(EntityManager EntityManager, Entity sceneEntity, Hash128 sceneGUID, RequestSceneLoaded requestSceneLoaded, Hash128 artifactHash) { // Resolve first (Even if the file doesn't exist we want to stop continously trying to load the section) var bufLen = EntityManager.AddBuffer <ResolvedSectionEntity>(sceneEntity).Length; Assert.AreEqual(0, bufLen); var sceneHeaderPath = ""; #if UNITY_EDITOR string[] paths = null; #endif bool useStreamingAssetPath = true; #if !UNITY_DOTSRUNTIME useStreamingAssetPath = SceneBundleHandle.UseAssetBundles; #endif if (useStreamingAssetPath) { sceneHeaderPath = EntityScenesPaths.GetLoadPath(sceneGUID, EntityScenesPaths.PathType.EntitiesHeader, -1); } else { #if UNITY_EDITOR AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out paths); sceneHeaderPath = EntityScenesPaths.GetLoadPathFromArtifactPaths(paths, EntityScenesPaths.PathType.EntitiesHeader); #endif } EntityManager.AddComponentData(sceneEntity, new ResolvedSceneHash { ArtifactHash = artifactHash }); var group = EntityManager.AddBuffer <LinkedEntityGroup>(sceneEntity); Assert.AreEqual(0, group.Length); group.Add(sceneEntity); // @TODO: AsyncReadManager currently crashes with empty path. // It should be possible to remove this after that is fixed. if (String.IsNullOrEmpty(sceneHeaderPath)) { #if UNITY_EDITOR var scenePath = AssetDatabaseCompatibility.GuidToPath(sceneGUID); var logPath = System.IO.Path.GetFullPath(System.IO.Path.Combine(UnityEngine.Application.dataPath, "../Logs")); Debug.LogError($"Loading Entity Scene failed because the entity header file couldn't be resolved. This might be caused by a failed import of the entity scene. Please take a look at the SubScene MonoBehaviour that references this scene or at the asset import worker log in {logPath}. scenePath={scenePath} guid={sceneGUID}"); #else Debug.LogError($"Loading Entity Scene failed because the entity header file couldn't be resolved: guid={sceneGUID}."); #endif return(false); } #if !UNITY_DOTSRUNTIME if (!BlobAssetReference <SceneMetaData> .TryRead(sceneHeaderPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef)) { #if UNITY_EDITOR Debug.LogError($"Loading Entity Scene failed because the entity header file was an old version or doesn't exist: guid={sceneGUID} path={sceneHeaderPath}"); #else Debug.LogError($"Loading Entity Scene failed because the entity header file was an old version or doesn't exist: {sceneGUID}\nNOTE: In order to load SubScenes in the player you have to use the new BuildConfiguration asset based workflow to build & run your player.\n{sceneHeaderPath}"); #endif return(false); } #else Assert.IsTrue(EntityManager.HasComponent <RequestSceneHeader>(sceneEntity), "You may only resolve a scene if the entity has a RequestSceneHeader component"); Assert.IsTrue(EntityManager.HasComponent <SceneMetaDataLoaded>(sceneEntity), "You may only resolve a scene if the entity has a SceneMetaDataLoaded component"); var sceneMetaDataLoaded = EntityManager.GetComponentData <SceneMetaDataLoaded>(sceneEntity); if (!sceneMetaDataLoaded.Success) { return(false); } var requestSceneHeader = EntityManager.GetComponentData <RequestSceneHeader>(sceneEntity); var sceneMetaDataRef = default(BlobAssetReference <SceneMetaData>); var asyncOp = new AsyncOp() { m_Handle = requestSceneHeader.IOHandle }; using (asyncOp) { unsafe { asyncOp.GetData(out var sceneData, out var sceneDataSize); if (!BlobAssetReference <SceneMetaData> .TryRead(sceneData, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out sceneMetaDataRef)) { Debug.LogError($"Loading Entity Scene failed because the entity header file was an old version or doesn't exist: {sceneGUID}\nNOTE: In order to load SubScenes in the player you have to use the new BuildConfiguration asset based workflow to build & run your player.\n{sceneHeaderPath}"); return(false); } } } #endif ref var sceneMetaData = ref sceneMetaDataRef.Value;