public IPsiSourceFile GetSourceFile(IHierarchyReference hierarchyReference, out Guid?guid) { guid = null; if (hierarchyReference == null) { return(null); } myShellLocks.AssertReadAccessAllowed(); switch (hierarchyReference) { case LocalReference localReference: var sourceFile = myManager[localReference.OwningPsiPersistentIndex]; guid = sourceFile != null?myMetaFileGuidCache.GetAssetGuid(sourceFile) : null; return(sourceFile); case ExternalReference externalReference: guid = externalReference.ExternalAssetGuid; var paths = myMetaFileGuidCache.GetAssetFilePathsFromGuid(guid.Value); if (paths.Count != 1) { return(null); } return(myPsiModule.TryGetFileByPath(paths[0], out var result) ? result : null); default: throw new InvalidOperationException(); } }
// Invariant : startGameObject is Transform Component if it is not stripped // This method traverse scene hierarchy via visiting transform components and push corresponding to transform GameObject into consumer private void ProcessSceneHierarchyFromComponentToRootInner(IYamlDocument startUnityObject, IUnitySceneProcessorConsumer consumer, IBlockMappingNode modifications) { var currentUnityObject = startUnityObject; while (currentUnityObject != null) { // Unity object could be stripped, it means, that corresponding real object belongs to another yaml file // Also, it has reference to prefab instance in current file, which stores all prefab modification if (IsStripped(currentUnityObject)) { var file = (IYamlFile)currentUnityObject.GetContainingFile(); var correspondingId = currentUnityObject.GetUnityObjectPropertyValue(GetCorrespondingSourceObjectProperty())?.AsFileID(); var prefabInstanceId = currentUnityObject.GetUnityObjectPropertyValue(GetPrefabInstanceProperty())?.AsFileID(); // assert not null if (correspondingId == null || prefabInstanceId == null) { return; } var prefabInstance = file.FindDocumentByAnchor(prefabInstanceId.fileID); var prefabSourceFile = myMetaFileGuidCache.GetAssetFilePathsFromGuid(correspondingId.guid); if (prefabSourceFile.Count > 1 || prefabSourceFile.Count == 0) { return; } myFactory.PsiModule.NotNull("externalFilesModuleFactory.PsiModule != null") .TryGetFileByPath(prefabSourceFile.First(), out var sourceFile); if (sourceFile == null) { return; } // [TODO] Is prefab file committed??? var prefabFile = (IYamlFile)sourceFile.GetDominantPsiFile <YamlLanguage>(); var prefabStartGameObject = prefabFile.FindDocumentByAnchor(correspondingId.fileID); if (!IsStripped(prefabStartGameObject)) { // !u!4 is transform. If tag is different, let's extract transform, there are two cases: // 1) prefabStartGameObject is GameObject(!u!1), take its transform // 2) prefabStartGameObject is Component, so get attached gameobject and from this gameobject take transform component if (!GetUnityObjectTag(prefabStartGameObject).Equals("!u!4")) { var attachedGameObject = prefabStartGameObject; if (!GetUnityObjectTag(prefabStartGameObject).Equals("!u!1")) { attachedGameObject = attachedGameObject.GetUnityObjectDocumentFromFileIDProperty(UnityYamlConstants .GameObjectProperty); } prefabStartGameObject = UnityObjectPsiUtil.FindTransformComponentForGameObject(attachedGameObject); } } var localModifications = UnityObjectPsiUtil.GetPrefabModification(prefabInstance); ProcessSceneHierarchyFromComponentToRootInner(prefabStartGameObject, consumer, localModifications); currentUnityObject = UnityObjectPsiUtil.GetTransformFromPrefabInstance(prefabInstance); } else { // assert that startGameObject is GameObject var father = currentUnityObject.GetUnityObjectDocumentFromFileIDProperty(UnityYamlConstants.FatherProperty); var gameObject = currentUnityObject.GetUnityObjectDocumentFromFileIDProperty(UnityYamlConstants.GameObjectProperty); consumer.ConsumeGameObject(gameObject, modifications); currentUnityObject = father; } } }
private IDictionary <long, IHierarchyElement> DoImport(Guid ownerGuid, AssetDocumentHierarchyElement assetDocumentHierarchyElement, HashSet <Guid> visitedGuid) { var result = new Dictionary <long, IHierarchyElement>(); foreach (var prefabInstanceHierarchy in assetDocumentHierarchyElement.GetPrefabInstanceHierarchies()) { var guid = prefabInstanceHierarchy.SourcePrefabGuid; var sourceFilePath = myMetaFileGuidCache.GetAssetFilePathsFromGuid(guid).FirstOrDefault(); if (sourceFilePath == null) { continue; } if (!myUnityExternalFilesPsiModule.TryGetFileByPath(sourceFilePath, out var sourceFile)) { continue; } var prefabHierarchy = assetDocumentHierarchyElement.AssetDocumentHierarchyElementContainer.GetAssetHierarchyFor(sourceFile); if (prefabHierarchy == null) { continue; } if (!myCache.TryGetFromCache(guid, out var importedElements)) { if (!visitedGuid.Contains(guid)) // invalid assets with cycles in prefab imports { myDependencies.Add(guid, ownerGuid); visitedGuid.Add(guid); importedElements = DoImport(guid, prefabHierarchy, visitedGuid); StoreResult(guid, importedElements); } else { importedElements = EmptyDictionary <long, IHierarchyElement> .Instance; } } foreach (var element in prefabHierarchy.Elements()) { if (element is IStrippedHierarchyElement) { continue; } if (element is IPrefabInstanceHierarchy) { continue; } var imported = element.Import(prefabInstanceHierarchy); if (imported == null) { continue; } result[imported.Location.LocalDocumentAnchor] = imported; } foreach (var element in importedElements.Values) { Assertion.Assert(!(element is IStrippedHierarchyElement), "element should be imported"); Assertion.Assert(!(element is IPrefabInstanceHierarchy), "prefab should be imported"); var imported = element.Import(prefabInstanceHierarchy); if (imported == null) { continue; } result[imported.Location.LocalDocumentAnchor] = imported; } } foreach (var value in result.Values) { var transform = value as ImportedTransformHierarchy; var reference = transform?.OwningGameObject; if (reference == null) { continue; } var importedGameObject = result.GetValueSafe(reference.Value.LocalDocumentAnchor) as ImportedGameObjectHierarchy; if (importedGameObject == null) { continue; } importedGameObject.TransformHierarchy = transform; } return(result); }