├── Editor.meta ├── Editor ├── DependencyGraph.cs ├── DependencyGraph.cs.meta ├── DependencyViewerAssembly.asmdef ├── DependencyViewerAssembly.asmdef.meta ├── Operations.meta ├── Operations │ ├── AssetDependencyResolverOperation.cs │ ├── AssetDependencyResolverOperation.cs.meta │ ├── DependencyViewerOperation.cs │ └── DependencyViewerOperation.cs.meta ├── Resolver.meta ├── Resolver │ ├── DependencyResolver.cs │ ├── DependencyResolver.cs.meta │ ├── DependencyResolverUtility.cs │ ├── DependencyResolverUtility.cs.meta │ ├── DependencyResolver_Dependencies.cs │ ├── DependencyResolver_Dependencies.cs.meta │ ├── DependencyResolver_References.cs │ └── DependencyResolver_References.cs.meta ├── Utility.meta ├── Utility │ ├── Attributes.meta │ ├── Attributes │ │ ├── EnumFlagsAttribute.cs │ │ └── EnumFlagsAttribute.cs.meta │ ├── DrawLine.cs │ ├── DrawLine.cs.meta │ ├── GameObjectUtility.cs │ ├── GameObjectUtility.cs.meta │ ├── PropertyDrawers.meta │ ├── PropertyDrawers │ │ ├── EnumFlagsAttributePropertyDrawer.cs │ │ └── EnumFlagsAttributePropertyDrawer.cs.meta │ ├── TreeLayout.cs │ └── TreeLayout.cs.meta ├── Viewer.meta └── Viewer │ ├── DependencyViewer.cs │ ├── DependencyViewer.cs.meta │ ├── DependencyViewerGraphDrawer.cs │ ├── DependencyViewerGraphDrawer.cs.meta │ ├── DependencyViewerNode.cs │ ├── DependencyViewerNode.cs.meta │ ├── DependencyViewerSettings.cs │ ├── DependencyViewerSettings.cs.meta │ ├── DependencyViewerSettingsOverlay.cs │ ├── DependencyViewerSettingsOverlay.cs.meta │ ├── DependencyViewerStatusBar.cs │ ├── DependencyViewerStatusBar.cs.meta │ ├── DependencyViewerUtility.cs │ └── DependencyViewerUtility.cs.meta ├── LICENSE.md ├── LICENSE.md.meta ├── Medias~ ├── Screenshot01.jpg └── Screenshot02.jpg ├── README.md └── README.md.meta /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 03aa7c9b92d39c7498301b2543799dd7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/DependencyGraph.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using UnityEngine; 6 | 7 | internal class DependencyViewerGraph 8 | { 9 | private DependencyViewerNode _refTargetNode; 10 | internal DependencyViewerNode RefTargetNode 11 | { 12 | get { return _refTargetNode; } 13 | set { _refTargetNode = value; } 14 | } 15 | 16 | public void CreateReferenceTargetNode(UnityEngine.Object refTarget) 17 | { 18 | _refTargetNode = new DependencyViewerNode(refTarget); 19 | } 20 | 21 | public void RearrangeNodesLayout() 22 | { 23 | OrganizeNodesInTree(DependencyViewerNode.NodeInputSide.Right); 24 | OrganizeNodesInTree(DependencyViewerNode.NodeInputSide.Left); 25 | CenterTreeToRoot(DependencyViewerNode.NodeInputSide.Right); 26 | } 27 | 28 | private void OrganizeNodesInTree(DependencyViewerNode.NodeInputSide treeSide) 29 | { 30 | InitializeNodes(treeSide); 31 | CalculateInitialY(treeSide); 32 | CalculateFinalPositions(_refTargetNode, treeSide); 33 | } 34 | 35 | private void InitializeNodes(DependencyViewerNode.NodeInputSide treeSide) 36 | { 37 | TreeLayout.ForeachNode_PostOrderTraversal(_refTargetNode, treeSide, (data) => 38 | { 39 | int direction = (treeSide == DependencyViewerNode.NodeInputSide.Right ? 1 : -1); 40 | data.currentNode.Position = new Vector2(data.depth * (data.currentNode.GetWidth() + DependencyViewerGraphDrawer.DistanceBetweenNodes.x) * direction, -1); 41 | data.currentNode.Mod = 0; 42 | }); 43 | } 44 | 45 | private void CalculateInitialY(DependencyViewerNode.NodeInputSide treeSide) 46 | { 47 | TreeLayout.ForeachNode_PostOrderTraversal(_refTargetNode, treeSide, (data) => 48 | { 49 | var node = data.currentNode; 50 | 51 | if (node.IsLeaf(data.TreeSide)) 52 | { 53 | if (node.IsFirstSibling(data.TreeSide)) 54 | { 55 | node.SetPositionY(0); 56 | } 57 | else 58 | { 59 | var previousSibling = node.GetPreviousSibling(data.TreeSide); 60 | node.SetPositionY(previousSibling.Position.y + previousSibling.GetHeight() + DependencyViewerGraphDrawer.DistanceBetweenNodes.y); 61 | } 62 | } 63 | else if (node.GetNumChildren(data.TreeSide) == 1) 64 | { 65 | if (node.IsFirstSibling(data.TreeSide)) 66 | { 67 | node.SetPositionY(node.GetChildren(data.TreeSide)[0].Position.y); 68 | } 69 | else 70 | { 71 | var previousSibling = node.GetPreviousSibling(data.TreeSide); 72 | node.SetPositionY(previousSibling.Position.y + previousSibling.GetHeight() + DependencyViewerGraphDrawer.DistanceBetweenNodes.y); 73 | node.Mod = node.Position.y - node.GetChildren(data.TreeSide)[0].Position.y; 74 | } 75 | } 76 | else 77 | { 78 | var prevChild = node.GetFirstChild(data.TreeSide); 79 | var nextChild = node.GetLastChild(data.TreeSide); 80 | float mid = (nextChild.Position.y - prevChild.Position.y) / 2; 81 | 82 | if (node.IsFirstSibling(data.TreeSide)) 83 | { 84 | node.SetPositionY(mid); 85 | } 86 | else 87 | { 88 | node.SetPositionY(node.GetPreviousSibling(data.TreeSide).Position.y + node.GetHeight() + DependencyViewerGraphDrawer.DistanceBetweenNodes.y); 89 | node.Mod = node.Position.y - mid; 90 | } 91 | } 92 | 93 | if (node.GetNumChildren(data.TreeSide) > 0 && !node.IsFirstSibling(data.TreeSide)) 94 | { 95 | CheckForConflicts(node, data.depth, data.TreeSide); 96 | } 97 | }); 98 | } 99 | 100 | private void CheckForConflicts(DependencyViewerNode node, int depth, DependencyViewerNode.NodeInputSide treeSide) 101 | { 102 | float minDistance = node.GetHeight() + DependencyViewerGraphDrawer.DistanceBetweenNodes.y; 103 | float shiftValue = 0.0f; 104 | 105 | var nodeContour = new Dictionary(); 106 | TreeLayout.GetStartContour(node, depth, treeSide, 0, ref nodeContour); 107 | 108 | var sibling = node.GetFirstSibling(treeSide); 109 | while (sibling != null && sibling != node) 110 | { 111 | var siblingContour = new Dictionary(); 112 | TreeLayout.GetEndContour(sibling, depth, treeSide, 0, ref siblingContour); 113 | 114 | int maxContourDepth = Mathf.Min(siblingContour.Keys.Max(), nodeContour.Keys.Max()); 115 | for (int level = depth + 1; level <= maxContourDepth; ++level) 116 | { 117 | float distance = nodeContour[level] - siblingContour[level]; 118 | if (distance + shiftValue < minDistance) 119 | { 120 | shiftValue = minDistance - distance; 121 | } 122 | } 123 | 124 | if (shiftValue > 0) 125 | { 126 | node.SetPositionY(node.Position.y + shiftValue); 127 | node.Mod += shiftValue; 128 | 129 | CenterNodesBetween(node, sibling, treeSide, depth); 130 | 131 | shiftValue = 0; 132 | } 133 | 134 | sibling = sibling.GetNextSibling(treeSide); 135 | } 136 | } 137 | 138 | private void CenterNodesBetween(DependencyViewerNode node, DependencyViewerNode sibling, DependencyViewerNode.NodeInputSide treeSide, int depth) 139 | { 140 | int firstNodeIdx = sibling.GetSiblingIndex(treeSide); 141 | int lastSiblingNodeIdx = node.GetSiblingIndex(treeSide); 142 | 143 | int numNodesBetween = (lastSiblingNodeIdx - firstNodeIdx) - 1; 144 | 145 | if (numNodesBetween > 0) 146 | { 147 | float distanceBetweenNodes = (node.Position.y - sibling.Position.y) / (numNodesBetween + 1); 148 | 149 | int count = 1; 150 | for (int i = firstNodeIdx + 1; i < lastSiblingNodeIdx; ++i) 151 | { 152 | var middleNode = node.GetParent(treeSide).GetChildren(treeSide)[i]; 153 | float desiredY = sibling.Position.y + (distanceBetweenNodes * count); 154 | float offset = desiredY - middleNode.Position.y; 155 | middleNode.SetPositionY(middleNode.Position.y + offset); 156 | middleNode.Mod += offset; 157 | 158 | ++count; 159 | } 160 | 161 | CheckForConflicts(node, depth, treeSide); 162 | } 163 | } 164 | 165 | private void CalculateFinalPositions(DependencyViewerNode node, DependencyViewerNode.NodeInputSide treeSide, float modSum = 0) 166 | { 167 | node.SetPositionY(node.Position.y + modSum); 168 | modSum += node.Mod; 169 | 170 | foreach (var child in node.GetChildren(treeSide)) 171 | { 172 | CalculateFinalPositions(child, treeSide, modSum); 173 | } 174 | } 175 | 176 | internal static void CreateNodeLink(DependencyViewerNode leftNode, DependencyViewerNode rightNode) 177 | { 178 | if (!leftNode.RightInputs.Contains(rightNode)) 179 | { 180 | leftNode.RightInputs.Add(rightNode); 181 | } 182 | 183 | if (!rightNode.LeftInputs.Contains(leftNode)) 184 | { 185 | rightNode.LeftInputs.Add(leftNode); 186 | } 187 | } 188 | 189 | private void CenterTreeToRoot(DependencyViewerNode.NodeInputSide side) 190 | { 191 | var children = _refTargetNode.GetChildren(side); 192 | 193 | if (children.Count > 1) 194 | { 195 | float size = _refTargetNode.GetLastChild(side).Position.y - _refTargetNode.GetFirstChild(side).Position.y; 196 | float actualY = _refTargetNode.GetFirstChild(side).Position.y; 197 | float desiredY = _refTargetNode.Position.y - size / 2.0f; 198 | float shiftY = desiredY - actualY; 199 | 200 | for (int i = 0; i < children.Count; ++i) 201 | { 202 | children[i].ForeachChildrenRecursively(side, (node) => node.SetPositionY(node.Position.y + shiftY)); 203 | } 204 | } 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /Editor/DependencyGraph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6b03c12e08686a247a62390fd64ea761 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/DependencyViewerAssembly.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dependencyviewer", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false 10 | } -------------------------------------------------------------------------------- /Editor/DependencyViewerAssembly.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63c1d5cfea599a740ba4db7a037ac21b 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Operations.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c6254619ca765248830d9fd3b0c8646 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Operations/AssetDependencyResolverOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | internal class AssetDependencyResolverOperation : DependencyViewerOperation 7 | { 8 | public int numTotalAssets { get; set; } 9 | public int numProcessedAssets { get; set; } 10 | public int numProcessedProperties { get; set; } 11 | public DependencyViewerNode node { get; set; } 12 | 13 | public UnityEngine.Object AssetBeingProcessed { get; set; } 14 | 15 | public override string GetStatus() 16 | { 17 | return string.Format("[{0:00.0}%][{1:0000}/{2:0000}][{3} -> {4}] Asset dependency resolving...", 18 | ((float) numProcessedAssets / numTotalAssets) * 100, 19 | numProcessedAssets, numTotalAssets, 20 | node.Name, AssetBeingProcessed.name); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Editor/Operations/AssetDependencyResolverOperation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9458a5d4bd218354588a6983d2638be4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Operations/DependencyViewerOperation.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | internal abstract class DependencyViewerOperation 6 | { 7 | public abstract string GetStatus(); 8 | } 9 | -------------------------------------------------------------------------------- /Editor/Operations/DependencyViewerOperation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87a58dd9b55e4094cb2780995441b40a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resolver.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7866ed9bd6bb214990198b1ba716d21 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.SceneManagement; 5 | using UnityEditor; 6 | using System; 7 | using System.Linq; 8 | using System.IO; 9 | 10 | internal class DependencyResolver 11 | { 12 | private DependencyViewerGraph _graph; 13 | private DependencyViewerSettings _settings; 14 | private DependencyResolver_References _referencesResolver; 15 | private DependencyResolver_Dependencies _dependenciesResolver; 16 | 17 | public DependencyResolver(DependencyViewerGraph graph, DependencyViewerSettings settings) 18 | { 19 | _graph = graph; 20 | _settings = settings; 21 | _referencesResolver = new DependencyResolver_References(graph, settings); 22 | _dependenciesResolver = new DependencyResolver_Dependencies(settings); 23 | } 24 | 25 | public IEnumerator BuildGraph() 26 | { 27 | if (_settings.FindDependencies) 28 | { 29 | _dependenciesResolver.FindDependencies(_graph.RefTargetNode, _settings.DependenciesDepth); 30 | } 31 | 32 | foreach (var currentOperation in _referencesResolver.FindReferences()) 33 | { 34 | yield return currentOperation; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e2dcbe32f458444ea7a4245f229c68e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolverUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | internal static class DependencyResolverUtility 7 | { 8 | public static bool IsObjectAnAsset(UnityEngine.Object obj) 9 | { 10 | return AssetDatabase.Contains(obj); 11 | } 12 | 13 | public static bool IsPrefab(UnityEngine.Object obj) 14 | { 15 | return IsObjectAnAsset(obj) && (obj is GameObject); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolverUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6b57e6e385e4ad349b3dd4fac4bbce03 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolver_Dependencies.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | internal class DependencyResolver_Dependencies 7 | { 8 | private DependencyViewerSettings _settings; 9 | 10 | public DependencyResolver_Dependencies(DependencyViewerSettings settings) 11 | { 12 | _settings = settings; 13 | } 14 | 15 | public void FindDependencies(DependencyViewerNode node, int depth = 1) 16 | { 17 | if (node.TargetObject is GameObject) 18 | { 19 | GameObject targetGameObject = node.TargetObject as GameObject; 20 | Component[] components = targetGameObject.GetComponents(); 21 | for (int i = 0; i < components.Length; ++i) 22 | { 23 | FindDependencies(node, components[i], depth); 24 | } 25 | 26 | if (DependencyResolverUtility.IsPrefab(node.TargetObject)) 27 | { 28 | UDGV.GameObjectUtility.ForeachChildrenGameObject(targetGameObject, (childGo) => 29 | { 30 | components = childGo.GetComponents(); 31 | for (int i = 0; i < components.Length; ++i) 32 | { 33 | FindDependencies(node, components[i], depth, targetGameObject); 34 | } 35 | }); 36 | } 37 | } 38 | else 39 | { 40 | FindDependencies(node, node.TargetObject, depth); 41 | } 42 | } 43 | 44 | private void FindDependencies(DependencyViewerNode node, UnityEngine.Object obj, int depth = 1, GameObject prefabRoot = null) 45 | { 46 | SerializedObject targetObjectSO = new SerializedObject(obj); 47 | SerializedProperty sp = targetObjectSO.GetIterator(); 48 | while (sp.NextVisible(true)) 49 | { 50 | if (sp.propertyType == SerializedPropertyType.ObjectReference && 51 | sp.objectReferenceValue != null && 52 | IsObjectAllowedBySettings(sp.objectReferenceValue)) 53 | { 54 | // Dependency found! 55 | DependencyViewerNode dependencyNode = new DependencyViewerNode(sp.objectReferenceValue); 56 | DependencyViewerGraph.CreateNodeLink(node, dependencyNode); 57 | if (prefabRoot != null) 58 | { 59 | Component comp = obj as Component; 60 | dependencyNode.SetAsPrefabContainerInfo(prefabRoot, comp.gameObject.name); 61 | } 62 | 63 | if (depth > 1) 64 | { 65 | FindDependencies(dependencyNode, sp.objectReferenceValue, depth - 1); 66 | } 67 | } 68 | } 69 | } 70 | 71 | private bool IsObjectAllowedBySettings(UnityEngine.Object obj) 72 | { 73 | return (_settings.CanObjectTypeBeIncluded(obj)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolver_Dependencies.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3027db639eb7d954eb3d32a2fec41256 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolver_References.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using UnityEditor; 6 | using UnityEngine; 7 | using UnityEngine.SceneManagement; 8 | 9 | internal class DependencyResolver_References 10 | { 11 | private const int NumAssetPropertiesReferencesResolvedPerFrame = 100; 12 | 13 | private DependencyViewerGraph _graph; 14 | private DependencyViewerSettings _settings; 15 | 16 | public DependencyResolver_References(DependencyViewerGraph graph, DependencyViewerSettings settings) 17 | { 18 | _graph = graph; 19 | _settings = settings; 20 | } 21 | 22 | public IEnumerable FindReferences() 23 | { 24 | if (_settings.SceneSearchType != DependencyViewerSettings.SceneSearchMode.NoSearch) 25 | { 26 | // Search references in scenes 27 | List currentOpenedScenes = DependencyViewerUtility.GetCurrentOpenedScenes(); 28 | if (_settings.FindReferences) 29 | { 30 | foreach (var currentOperation in FindReferencesAmongGameObjects(_graph.RefTargetNode, currentOpenedScenes)) 31 | { 32 | yield return currentOperation; 33 | } 34 | } 35 | } 36 | 37 | bool searchOnlyInCurrentScene = (_settings.SceneSearchType == DependencyViewerSettings.SceneSearchMode.SearchOnlyInCurrentScene); 38 | if (_settings.FindReferences && !searchOnlyInCurrentScene) 39 | { 40 | // Search references in assets 41 | foreach (var currentOperation in FindReferencesAmongAssets(_graph.RefTargetNode)) 42 | { 43 | yield return currentOperation; 44 | } 45 | } 46 | } 47 | 48 | private IEnumerable FindReferencesAmongGameObjects(DependencyViewerNode node, List scenes) 49 | { 50 | AssetDependencyResolverOperation operationStatus = new AssetDependencyResolverOperation(); 51 | operationStatus.node = node; 52 | 53 | List allGameObjects = GetAllGameObjectsFromScenes(scenes); 54 | operationStatus.numTotalAssets = allGameObjects.Count; 55 | 56 | int numPropertiesCheck = 0; 57 | for (int i = 0; i < allGameObjects.Count; ++i) 58 | { 59 | GameObject currentGo = allGameObjects[i]; 60 | operationStatus.AssetBeingProcessed = currentGo; 61 | 62 | Component[] components = currentGo.GetComponents(); 63 | for (int componentIndex = 0; componentIndex < components.Length; ++componentIndex) 64 | { 65 | Component component = components[componentIndex]; 66 | if (component == null) 67 | { 68 | continue; 69 | } 70 | 71 | SerializedObject componentSO = new SerializedObject(component); 72 | SerializedProperty componentSP = componentSO.GetIterator(); 73 | 74 | while (componentSP.NextVisible(true)) 75 | { 76 | // Reference found! 77 | if (componentSP.propertyType == SerializedPropertyType.ObjectReference && 78 | componentSP.objectReferenceValue == node.TargetObject && 79 | IsObjectAllowedBySettings(component)) 80 | { 81 | DependencyViewerNode referenceNode = new DependencyViewerNode(component); 82 | DependencyViewerGraph.CreateNodeLink(referenceNode, node); 83 | } 84 | 85 | ++numPropertiesCheck; 86 | if (numPropertiesCheck > NumAssetPropertiesReferencesResolvedPerFrame) 87 | { 88 | numPropertiesCheck = 0; 89 | yield return operationStatus; 90 | } 91 | } 92 | } 93 | 94 | ++operationStatus.numProcessedAssets; 95 | } 96 | } 97 | 98 | private IEnumerable FindReferencesAmongAssets(DependencyViewerNode node) 99 | { 100 | string[] excludeFilters = _settings.ExcludeAssetFilters.Split(','); 101 | 102 | var allLocalAssetPaths = from assetPath in AssetDatabase.GetAllAssetPaths() 103 | where assetPath.StartsWith("Assets/") && !IsAssetPathExcluded(assetPath, ref excludeFilters) 104 | select assetPath; 105 | 106 | AssetDependencyResolverOperation operationStatus = new AssetDependencyResolverOperation 107 | { 108 | node = node, 109 | numTotalAssets = allLocalAssetPaths.Count() 110 | }; 111 | 112 | foreach (string assetPath in allLocalAssetPaths) 113 | { 114 | ++operationStatus.numProcessedAssets; 115 | 116 | UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(assetPath); 117 | if (obj != null) 118 | { 119 | bool isPrefab = (obj is GameObject); 120 | if (isPrefab) 121 | { 122 | GameObject prefab = obj as GameObject; 123 | foreach (var op in FindReferencesAmongPrefabChildren(node, prefab, operationStatus, prefab)) 124 | { 125 | yield return op; 126 | } 127 | } 128 | else 129 | { 130 | foreach (var op in FindReferencesOnUnityObject(node, obj, operationStatus)) 131 | { 132 | yield return op; 133 | } 134 | } 135 | } 136 | } 137 | } 138 | 139 | private IEnumerable FindReferencesOnUnityObject( 140 | DependencyViewerNode node, 141 | UnityEngine.Object obj, 142 | AssetDependencyResolverOperation op, 143 | GameObject prefabRoot = null) 144 | { 145 | SerializedObject objSO = new SerializedObject(obj); 146 | SerializedProperty sp = objSO.GetIterator(); 147 | while (sp.NextVisible(true)) 148 | { 149 | if (IsPropertyADependency(sp, node)) 150 | { 151 | // Reference found! 152 | DependencyViewerNode reference = new DependencyViewerNode(obj); 153 | DependencyViewerGraph.CreateNodeLink(reference, node); 154 | if (prefabRoot != null) 155 | { 156 | reference.SetAsPrefabContainerInfo(prefabRoot, (obj as Component).gameObject.name); 157 | } 158 | } 159 | 160 | ++op.numProcessedProperties; 161 | 162 | if (op.numProcessedProperties > NumAssetPropertiesReferencesResolvedPerFrame) 163 | { 164 | op.AssetBeingProcessed = obj; 165 | 166 | op.numProcessedProperties = 0; 167 | yield return op; 168 | } 169 | } 170 | } 171 | 172 | private IEnumerable FindReferencesAmongPrefabChildren( 173 | DependencyViewerNode node, 174 | GameObject gameObject, 175 | AssetDependencyResolverOperation op, 176 | GameObject prefabRoot) 177 | { 178 | // Find references among the components of the GameObject... 179 | Component[] components = gameObject.GetComponents(); 180 | for (int i = 0; i < components.Length; ++i) 181 | { 182 | foreach (var operation in FindReferencesOnUnityObject(node, components[i], op, prefabRoot)) 183 | { 184 | yield return operation; 185 | } 186 | } 187 | 188 | // ...then make same thing on children 189 | Transform trans = gameObject.transform; 190 | for (int i = 0; i < trans.childCount; ++i) 191 | { 192 | GameObject child = trans.GetChild(i).gameObject; 193 | foreach (var operation in FindReferencesAmongPrefabChildren(node, child, op, prefabRoot)) 194 | { 195 | yield return operation; 196 | } 197 | } 198 | } 199 | 200 | private bool IsPropertyADependency(SerializedProperty sp, DependencyViewerNode node) 201 | { 202 | return sp.propertyType == SerializedPropertyType.ObjectReference && 203 | sp.objectReferenceValue == node.TargetObject && 204 | IsObjectAllowedBySettings(sp.objectReferenceValue); 205 | } 206 | 207 | private List GetAllGameObjectsFromScenes(List scenes) 208 | { 209 | List gameObjects = new List(); 210 | List gameObjectsToCheck = new List(); 211 | 212 | List rootGameObjects = new List(); 213 | for (int sceneIdx = 0; sceneIdx < scenes.Count; ++sceneIdx) 214 | { 215 | Scene scene = scenes[sceneIdx]; 216 | scene.GetRootGameObjects(rootGameObjects); 217 | gameObjectsToCheck.AddRange(rootGameObjects); 218 | } 219 | 220 | for (int gameObjectsToCheckIdx = 0; gameObjectsToCheckIdx < gameObjectsToCheck.Count; ++gameObjectsToCheckIdx) 221 | { 222 | GameObject currentGo = gameObjectsToCheck[gameObjectsToCheckIdx]; 223 | for (int childIdx = 0; childIdx < currentGo.transform.childCount; ++childIdx) 224 | { 225 | gameObjectsToCheck.Add(currentGo.transform.GetChild(childIdx).gameObject); 226 | } 227 | gameObjects.Add(currentGo); 228 | } 229 | 230 | return gameObjects; 231 | } 232 | 233 | private bool IsObjectAllowedBySettings(UnityEngine.Object obj) 234 | { 235 | return (_settings.CanObjectTypeBeIncluded(obj)); 236 | } 237 | 238 | private bool IsAssetPathExcluded(string assetPath, ref string[] excludeFilters) 239 | { 240 | for (int i = 0; i < excludeFilters.Length; ++i) 241 | { 242 | if (assetPath.EndsWith(excludeFilters[i])) 243 | { 244 | return true; 245 | } 246 | } 247 | 248 | if (_settings.ReferencesAssetDirectories != null && 249 | _settings.ReferencesAssetDirectories.Length > 0) 250 | { 251 | bool isAssetAmongReferencesDirectory = false; 252 | string assetFullPath = Path.GetFullPath(assetPath); 253 | for (int i = 0; i < _settings.ReferencesAssetDirectories.Length; ++i) 254 | { 255 | if (Directory.Exists(_settings.ReferencesAssetDirectories[i])) 256 | { 257 | string referenceAssetFullPath = Path.GetFullPath(_settings.ReferencesAssetDirectories[i]); 258 | if (assetFullPath.StartsWith(referenceAssetFullPath)) 259 | { 260 | isAssetAmongReferencesDirectory = true; 261 | break; 262 | } 263 | } 264 | } 265 | 266 | return !isAssetAmongReferencesDirectory; 267 | } 268 | 269 | return false; 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /Editor/Resolver/DependencyResolver_References.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4fe7c6e94c3369a4d9a01ca8730978f6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Utility.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 949eaf5d289a52d4b8beea14efbead9a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Utility/Attributes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e560009395025ae4f9e134641e841d70 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Utility/Attributes/EnumFlagsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | internal class EnumFlagsAttribute : PropertyAttribute { } -------------------------------------------------------------------------------- /Editor/Utility/Attributes/EnumFlagsAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da1c875f8f2ca8940ba8bac4831f581a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Utility/DrawLine.cs: -------------------------------------------------------------------------------- 1 | // Credits : http://wiki.unity3d.com/index.php/DrawLine 2 | // Then fix because it didn't work 3 | 4 | using System; 5 | using UnityEngine; 6 | 7 | internal class Drawing 8 | { 9 | //**************************************************************************************************** 10 | // static function DrawLine(rect : Rect) : void 11 | // static function DrawLine(rect : Rect, color : Color) : void 12 | // static function DrawLine(rect : Rect, width : float) : void 13 | // static function DrawLine(rect : Rect, color : Color, width : float) : void 14 | // static function DrawLine(Vector2 pointA, Vector2 pointB) : void 15 | // static function DrawLine(Vector2 pointA, Vector2 pointB, color : Color) : void 16 | // static function DrawLine(Vector2 pointA, Vector2 pointB, width : float) : void 17 | // static function DrawLine(Vector2 pointA, Vector2 pointB, color : Color, width : float) : void 18 | // 19 | // Draws a GUI line on the screen. 20 | // 21 | // DrawLine makes up for the severe lack of 2D line rendering in the Unity runtime GUI system. 22 | // This function works by drawing a 1x1 texture filled with a color, which is then scaled 23 | // and rotated by altering the GUI matrix. The matrix is restored afterwards. 24 | //**************************************************************************************************** 25 | 26 | public static Texture2D lineTex; 27 | 28 | public static void DrawLine(Rect rect) { DrawLine(rect, GUI.contentColor, 1.0f); } 29 | public static void DrawLine(Rect rect, Color color) { DrawLine(rect, color, 1.0f); } 30 | public static void DrawLine(Rect rect, float width) { DrawLine(rect, GUI.contentColor, width); } 31 | public static void DrawLine(Rect rect, Color color, float width) { DrawLine(new Vector2(rect.x, rect.y), new Vector2(rect.x + rect.width, rect.y + rect.height), color, width); } 32 | public static void DrawLine(Vector2 pointA, Vector2 pointB) { DrawLine(pointA, pointB, GUI.contentColor, 1.0f); } 33 | public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color) { DrawLine(pointA, pointB, color, 1.0f); } 34 | public static void DrawLine(Vector2 pointA, Vector2 pointB, float width) { DrawLine(pointA, pointB, GUI.contentColor, width); } 35 | public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width) 36 | { 37 | // Save the current GUI matrix, since we're going to make changes to it. 38 | Matrix4x4 matrix = GUI.matrix; 39 | 40 | // Generate a single pixel texture if it doesn't exist 41 | if (!lineTex) { lineTex = new Texture2D(1, 1); } 42 | 43 | // Store current GUI color, so we can switch it back later, 44 | // and set the GUI color to the color parameter 45 | Color savedColor = GUI.color; 46 | GUI.color = color; 47 | 48 | // Determine the angle of the line. 49 | float angle = Vector3.Angle(pointB - pointA, Vector2.right); 50 | 51 | // Vector3.Angle always returns a positive number. 52 | // If pointB is above pointA, then angle needs to be negative. 53 | if (pointA.y > pointB.y) { angle = -angle; } 54 | 55 | // Use ScaleAroundPivot to adjust the size of the line. 56 | // We could do this when we draw the texture, but by scaling it here we can use 57 | // non-integer values for the width and length (such as sub 1 pixel widths). 58 | // Note that the pivot point is at +.5 from pointA.y, this is so that the width of the line 59 | // is centered on the origin at pointA. 60 | 61 | // Set the rotation for the line. 62 | // The angle was calculated with pointA as the origin. 63 | GUIUtility.RotateAroundPivot(angle, pointA); 64 | 65 | // Finally, draw the actual line. 66 | // We're really only drawing a 1x1 texture from pointA. 67 | // The matrix operations done with ScaleAroundPivot and RotateAroundPivot will make this 68 | // render with the proper width, length, and angle. 69 | GUI.DrawTexture(new Rect(pointA.x, pointA.y - 0.5f * width, Vector3.Distance(pointA, pointB), width), lineTex); 70 | 71 | // We're done. Restore the GUI matrix and GUI color to whatever they were before. 72 | GUI.matrix = matrix; 73 | GUI.color = savedColor; 74 | } 75 | } -------------------------------------------------------------------------------- /Editor/Utility/DrawLine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b8f9a10e63f16d04dbca950cd0edc954 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Utility/GameObjectUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace UDGV 7 | { 8 | internal static class GameObjectUtility 9 | { 10 | public static void ForeachChildrenGameObject(GameObject rootGameObject, Action callback) 11 | { 12 | Transform rootTransform = rootGameObject.transform; 13 | for (int i = 0; i < rootTransform.childCount; ++i) 14 | { 15 | Transform childTransform = rootTransform.GetChild(i); 16 | callback(childTransform.gameObject); 17 | ForeachChildrenGameObject(childTransform.gameObject, callback); 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Editor/Utility/GameObjectUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a51bbbe99765ba4da460a79d6619748 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Utility/PropertyDrawers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 47b67b97093cc6f49b860d5303ea1371 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Utility/PropertyDrawers/EnumFlagsAttributePropertyDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | [CustomPropertyDrawer(typeof(EnumFlagsAttribute))] 7 | internal class EnumFlagsAttributePropertyDrawer : PropertyDrawer 8 | { 9 | public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label) 10 | { 11 | _property.intValue = EditorGUI.MaskField(_position, _label, _property.intValue, _property.enumNames); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Editor/Utility/PropertyDrawers/EnumFlagsAttributePropertyDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e8424a528ac25f64db6e1ca6240fc556 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Utility/TreeLayout.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | internal class TreeLayout 7 | { 8 | public class PostOrderTraversalData 9 | { 10 | public PostOrderTraversalData(DependencyViewerNode.NodeInputSide treeSide) 11 | { 12 | _treeSide = treeSide; 13 | } 14 | 15 | public DependencyViewerNode parentNode; 16 | public DependencyViewerNode currentNode; 17 | public int childIdx; 18 | public int depth; 19 | private DependencyViewerNode.NodeInputSide _treeSide; 20 | 21 | public DependencyViewerNode.NodeInputSide TreeSide 22 | { get { return _treeSide; } } 23 | } 24 | 25 | public static void ForeachNode_PostOrderTraversal( 26 | DependencyViewerNode rootNode, 27 | DependencyViewerNode.NodeInputSide side, 28 | Action callback) 29 | { 30 | ForeachNode_PostOrderTraversal(null, rootNode, side, callback, 0, 0); 31 | } 32 | 33 | private static void ForeachNode_PostOrderTraversal( 34 | DependencyViewerNode parentNode, 35 | DependencyViewerNode rootNode, 36 | DependencyViewerNode.NodeInputSide side, 37 | Action callback, int childIdx, int depth) 38 | { 39 | List children = rootNode.GetInputNodesFromSide(side); 40 | for (int i = 0; i < children.Count; ++i) 41 | { 42 | ForeachNode_PostOrderTraversal(rootNode, children[i], side, callback, i, depth + 1); 43 | } 44 | 45 | PostOrderTraversalData data = new PostOrderTraversalData(side) 46 | { 47 | childIdx = childIdx, 48 | currentNode = rootNode, 49 | parentNode = parentNode, 50 | depth = depth 51 | }; 52 | callback(data); 53 | } 54 | 55 | public static void GetStartContour(DependencyViewerNode node, int depth, DependencyViewerNode.NodeInputSide childrenSide, float modSum, ref Dictionary values) 56 | { 57 | GetContour(node, depth, childrenSide, Mathf.Min, modSum, ref values); 58 | } 59 | 60 | public static void GetEndContour(DependencyViewerNode node, int depth, DependencyViewerNode.NodeInputSide childrenSide, float modSum, ref Dictionary values) 61 | { 62 | GetContour(node, depth, childrenSide, Mathf.Max, modSum, ref values); 63 | } 64 | 65 | private static void GetContour( 66 | DependencyViewerNode node, 67 | int depth, 68 | DependencyViewerNode.NodeInputSide childrenSide, 69 | Func getContourCallback, 70 | float modSum, 71 | ref Dictionary values) 72 | { 73 | if (!values.ContainsKey(depth)) 74 | { 75 | values.Add(depth, node.Position.y + modSum); 76 | } 77 | else 78 | { 79 | values[depth] = getContourCallback(values[depth], node.Position.y + modSum); 80 | } 81 | 82 | modSum += node.Mod; 83 | 84 | var children = node.GetInputNodesFromSide(childrenSide); 85 | foreach (var child in children) 86 | { 87 | GetContour(child, depth + 1, childrenSide, getContourCallback, modSum, ref values); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Editor/Utility/TreeLayout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e58ba4f733193841bb732ea525426bd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5bc58d43c2ddff4499d5471b23bfa21d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using System; 6 | using UnityEngine.SceneManagement; 7 | 8 | [ExecuteInEditMode] 9 | public class DependencyViewer : EditorWindow 10 | { 11 | public UnityEngine.Object refTarget; 12 | private DependencyViewerSettings _settings; 13 | internal DependencyViewerSettings Settings 14 | { 15 | get { return _settings; } 16 | set { _settings = value; } 17 | } 18 | 19 | private DependencyViewerGraph _graph; 20 | private DependencyViewerGraphDrawer _graphDrawer; 21 | private DependencyViewerSettingsOverlay _settingsOverlay; 22 | private DependencyViewerStatusBar _statusBar; 23 | private DependencyResolver _resolver; 24 | 25 | private bool _readyToDrag; 26 | private bool _isDragging; 27 | 28 | private IEnumerator _resolverWorkHandle; 29 | 30 | [MenuItem("GameObject/View Dependencies", priority = 10)] 31 | private static void ViewReferencesFromMenuCommand(MenuCommand menuCommand) 32 | { 33 | ViewReferences(); 34 | } 35 | 36 | [MenuItem("Assets/View Dependencies")] 37 | public static void ViewReferences() 38 | { 39 | DependencyViewer referenceViewer = EditorWindow.GetWindow("Dependency Viewer"); 40 | referenceViewer.ViewDependencies(Selection.activeObject); 41 | } 42 | 43 | public void ViewDependencies(UnityEngine.Object targetObject) 44 | { 45 | refTarget = targetObject; 46 | BuildGraph(); 47 | } 48 | 49 | IEnumerator GetEnumerator() 50 | { 51 | yield return null; 52 | } 53 | 54 | private void OnEnable() 55 | { 56 | _graph = new DependencyViewerGraph(); 57 | _graphDrawer = new DependencyViewerGraphDrawer(_graph); 58 | _settings = DependencyViewerSettings.Create(); 59 | _settings.Load(); 60 | _settingsOverlay = new DependencyViewerSettingsOverlay(_settings); 61 | _resolver = new DependencyResolver(_graph, _settings); 62 | _statusBar = new DependencyViewerStatusBar(); 63 | 64 | _settings.onSettingsChanged += OnSettingsChanged; 65 | _graphDrawer.requestViewDependency += ViewDependencies; 66 | 67 | if (refTarget != null) 68 | { 69 | BuildGraph(); 70 | } 71 | 72 | // If the active object is already a DependencyViewerSettings, 73 | // it probably means that some old settings are actually inspected. 74 | // Update the active object to now use the new settings object. 75 | if (Selection.activeObject is DependencyViewerSettings) 76 | { 77 | Selection.activeObject = _settings; 78 | } 79 | } 80 | 81 | private void OnDisable() 82 | { 83 | _settings.Save(); 84 | } 85 | 86 | private void OnSettingsChanged() 87 | { 88 | BuildGraph(); 89 | } 90 | 91 | public void BuildGraph() 92 | { 93 | _graph.CreateReferenceTargetNode(refTarget); 94 | _resolverWorkHandle = _resolver.BuildGraph(); 95 | _resolverWorkHandle.MoveNext(); 96 | _graph.RearrangeNodesLayout(); 97 | CenterViewerOnGraph(); 98 | } 99 | 100 | private void Update() 101 | { 102 | if (_resolverWorkHandle != null) 103 | { 104 | bool isResolverWorkCompleted = !_resolverWorkHandle.MoveNext(); 105 | 106 | // Update status bar according to current operation state 107 | DependencyViewerOperation currentOperation = _resolverWorkHandle.Current; 108 | if (currentOperation != null) 109 | { 110 | _statusBar.SetText(currentOperation.GetStatus()); 111 | } 112 | 113 | _graph.RearrangeNodesLayout(); 114 | if (isResolverWorkCompleted) 115 | { 116 | _resolverWorkHandle = null; 117 | _statusBar.SetText("Completed!"); 118 | } 119 | 120 | Repaint(); 121 | } 122 | } 123 | 124 | private void CenterViewerOnGraph() 125 | { 126 | _graphDrawer.CenterViewerOnGraph(position); 127 | } 128 | 129 | private void OnGUI() 130 | { 131 | if (refTarget == null) 132 | { 133 | return; 134 | } 135 | 136 | _graphDrawer.Draw(position); 137 | _settingsOverlay.Draw(); 138 | _statusBar.Draw(position); 139 | 140 | UpdateInputs(); 141 | } 142 | 143 | private void UpdateInputs() 144 | { 145 | Event e = Event.current; 146 | 147 | Rect localWindowRect = position; 148 | localWindowRect.x = localWindowRect.y = 0; 149 | 150 | if (e.type == EventType.MouseDown && e.button == 0 && localWindowRect.Contains(e.mousePosition)) 151 | { 152 | _readyToDrag = true; 153 | } 154 | 155 | if ((_readyToDrag || _isDragging) && e.type == EventType.MouseDrag && e.button == 0) 156 | { 157 | _readyToDrag = false; 158 | _isDragging = true; 159 | 160 | Vector2 offset = e.delta; 161 | _graphDrawer.ShiftView(-offset); 162 | 163 | Repaint(); 164 | } 165 | 166 | if (_isDragging && e.type == EventType.MouseUp && e.button == 0) 167 | { 168 | _isDragging = false; 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b8befa1f37ba28489ceb31b9f8864c2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerGraphDrawer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using System; 6 | 7 | internal class DependencyViewerGraphDrawer 8 | { 9 | enum NodeInputSide { Left, Right } 10 | 11 | internal static readonly Vector2 DistanceBetweenNodes = new Vector2(30, 30); 12 | internal static readonly Vector2 NodeInsidePadding = new Vector2(10, 10); 13 | internal const float NodeWidth = 200; 14 | internal const float NodeHeight = 50; 15 | internal const float LinkWidth = 2; 16 | internal static readonly Color LinkColor = Color.black; 17 | 18 | public event Action requestViewDependency; 19 | 20 | private DependencyViewerGraph _graph; 21 | private GUIStyle _titleLabelStyle; 22 | 23 | private Vector2 _screenOffset; 24 | public Vector2 ScreenOffset 25 | { 26 | get { return _screenOffset; } 27 | set { _screenOffset = value; } 28 | } 29 | 30 | public DependencyViewerNode RefTargetNode 31 | { get { return _graph.RefTargetNode; } } 32 | 33 | private Rect _lastWindowRect; 34 | 35 | public DependencyViewerGraphDrawer(DependencyViewerGraph graph) 36 | { 37 | _graph = graph; 38 | _titleLabelStyle = new GUIStyle() 39 | { 40 | alignment = TextAnchor.MiddleCenter 41 | }; 42 | } 43 | 44 | public void CenterViewerOnGraph(Rect windowRect) 45 | { 46 | if (_graph == null) 47 | { 48 | return; 49 | } 50 | 51 | Vector2 size = _graph.RefTargetNode.GetSize(); 52 | _screenOffset = new Vector2(-(windowRect.width - size.x) / 2, -(windowRect.height - size.y) / 2); 53 | } 54 | 55 | public void ShiftView(Vector2 delta) 56 | { 57 | _screenOffset += delta; 58 | } 59 | 60 | public void Draw(Rect windowRect) 61 | { 62 | _lastWindowRect = windowRect; 63 | 64 | if (RefTargetNode != null) 65 | { 66 | DrawHierarchyNodesFromRefTargetNode(); 67 | DrawLinksFromRefTargetNode(); 68 | } 69 | } 70 | 71 | private void DrawHierarchyNodesFromRefTargetNode() 72 | { 73 | DrawNode(RefTargetNode); 74 | DrawInputsNodesRecursively(RefTargetNode.LeftInputs, NodeInputSide.Left); 75 | DrawInputsNodesRecursively(RefTargetNode.RightInputs, NodeInputSide.Right); 76 | } 77 | 78 | private void DrawInputsNodesRecursively(List nodes, NodeInputSide inputSide) 79 | { 80 | for (int i = 0; i < nodes.Count; ++i) 81 | { 82 | DrawNode(nodes[i]); 83 | DrawInputsNodesRecursively(inputSide == NodeInputSide.Left ? nodes[i].LeftInputs : nodes[i].RightInputs, inputSide); 84 | } 85 | } 86 | 87 | private Vector2 GetRelativePosition(Vector2 worldPosition) 88 | { 89 | return new Vector2(worldPosition.x - _screenOffset.x, worldPosition.y - _screenOffset.y); 90 | } 91 | 92 | private void DrawNode(DependencyViewerNode node) 93 | { 94 | Rect boxRect = new Rect(GetRelativePosition(node.Position), node.GetSize()); 95 | 96 | Rect localWindowRect = GetLocalWindowRect(); 97 | if (!localWindowRect.Overlaps(boxRect)) 98 | { 99 | //Debug.Log("Node " + node.Name + " not drawn"); 100 | return; 101 | } 102 | 103 | GUI.Box(boxRect, GUIContent.none, GUI.skin.FindStyle("flow node 0")); 104 | 105 | DrawNodeTitleBar(node, boxRect); 106 | 107 | Rect boxInsideRect = 108 | new Rect( 109 | boxRect.x + NodeInsidePadding.x, 110 | boxRect.y + NodeInsidePadding.y + EditorGUIUtility.singleLineHeight, 111 | boxRect.width - NodeInsidePadding.x * 2, 112 | boxRect.height - NodeInsidePadding.y * 2); 113 | 114 | GUILayout.BeginArea(boxInsideRect); 115 | { 116 | bool allowSceneObjects = false; 117 | EditorGUILayout.ObjectField(node.TargetObject, node.TargetObject.GetType(), allowSceneObjects); 118 | 119 | if (node.PrefabContainer != null) 120 | { 121 | DrawPrefabContainer(node); 122 | } 123 | } 124 | GUILayout.EndArea(); 125 | } 126 | 127 | private void DrawPrefabContainer(DependencyViewerNode node) 128 | { 129 | bool allowSceneObjects = false; 130 | EditorGUILayout.BeginHorizontal(); 131 | { 132 | GUIContent label = new GUIContent("Prefab", $"Prefab reference, on GameObject named '{node.GameObjectNameAsPrefabChild}'"); 133 | EditorGUILayout.LabelField(label, GUILayout.Width(40)); 134 | EditorGUILayout.ObjectField(node.PrefabContainer, typeof(GameObject), allowSceneObjects); 135 | } 136 | EditorGUILayout.EndHorizontal(); 137 | } 138 | 139 | private void DrawNodeTitleBar(DependencyViewerNode node, Rect boxRect) 140 | { 141 | Rect boxTitleRect = 142 | new Rect( 143 | boxRect.x, boxRect.y + 4, 144 | boxRect.width, EditorGUIUtility.singleLineHeight); 145 | 146 | GUI.Label(boxTitleRect, node.Name, _titleLabelStyle); 147 | 148 | if (node != RefTargetNode) 149 | { 150 | Vector2 buttonSize = Vector2.one * 15; 151 | Vector2 padding = new Vector2(10, 5); 152 | 153 | Rect viewDependencyRect = 154 | new Rect(boxRect.x + boxRect.width - (padding.x + buttonSize.x), boxRect.y + padding.y, buttonSize.x, buttonSize.y); 155 | 156 | if (GUI.Button(viewDependencyRect, new GUIContent("", "View dependency for this object"), GUI.skin.FindStyle("Icon.ExtrapolationContinue"))) 157 | { 158 | requestViewDependency(node.TargetObject); 159 | } 160 | } 161 | } 162 | 163 | private void DrawLinksFromRefTargetNode() 164 | { 165 | DrawNodeLinks(RefTargetNode, RefTargetNode.LeftInputs, NodeInputSide.Left); 166 | DrawNodeLinks(RefTargetNode, RefTargetNode.RightInputs, NodeInputSide.Right); 167 | } 168 | 169 | private void DrawNodeLinks(DependencyViewerNode node, List inputs, NodeInputSide inputSide) 170 | { 171 | for (int i = 0; i < inputs.Count; ++i) 172 | { 173 | DependencyViewerNode inputNode = inputs[i]; 174 | 175 | DependencyViewerNode leftNode = (inputSide == NodeInputSide.Left ? node : inputNode); 176 | DependencyViewerNode rightNode = (inputSide == NodeInputSide.Right ? node : inputNode); 177 | 178 | 179 | Vector2 start = GetRelativePosition(leftNode.GetLeftInputAnchorPosition()); 180 | Vector2 end = GetRelativePosition(rightNode.GetRightInputAnchorPosition()); 181 | 182 | Drawing.DrawLine(start, end, LinkColor, LinkWidth); 183 | 184 | DrawNodeLinks( 185 | inputNode, 186 | inputSide == NodeInputSide.Left ? inputNode.LeftInputs : inputNode.RightInputs, 187 | inputSide); 188 | } 189 | } 190 | 191 | private Rect GetLocalWindowRect() 192 | { 193 | Rect localWindowRect = _lastWindowRect; 194 | localWindowRect.x = 0; 195 | localWindowRect.y = 0; 196 | return localWindowRect; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerGraphDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed03ca67a57927540bd10447cef9a46c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | internal class DependencyViewerNode 8 | { 9 | public enum NodeInputSide { Left, Right } 10 | 11 | public string Name 12 | { 13 | get 14 | { 15 | if (_targetObject == null) 16 | { 17 | return "(null)"; 18 | } 19 | 20 | string suffix = (_targetObject is UnityEditor.MonoScript) ? " (Script)" : string.Empty; 21 | 22 | return $"{_targetObject.name}{suffix}"; 23 | } 24 | } 25 | 26 | private UnityEngine.Object _targetObject; 27 | public UnityEngine.Object TargetObject 28 | { 29 | get { return _targetObject; } 30 | private set { _targetObject = value; } 31 | } 32 | 33 | public string GameObjectNameAsPrefabChild { get; private set; } 34 | public GameObject PrefabContainer { get; private set; } 35 | 36 | private Vector2 _position; 37 | public Vector2 Position 38 | { 39 | get { return _position; } 40 | set { _position = value; } 41 | } 42 | 43 | private List _leftInputs; 44 | public List LeftInputs 45 | { 46 | get { return _leftInputs; } 47 | set { _leftInputs = value; } 48 | } 49 | 50 | private List _rightInputs; 51 | public List RightInputs 52 | { 53 | get { return _rightInputs; } 54 | set { _rightInputs = value; } 55 | } 56 | 57 | private float _mod; 58 | public float Mod 59 | { 60 | get { return _mod; } 61 | set { _mod = value; } 62 | } 63 | 64 | 65 | public DependencyViewerNode(UnityEngine.Object targetObject) 66 | { 67 | _targetObject = targetObject; 68 | _leftInputs = new List(); 69 | _rightInputs = new List(); 70 | } 71 | 72 | public void SetAsPrefabContainerInfo(GameObject prefabContainer, string gameObjectName) 73 | { 74 | PrefabContainer = prefabContainer; 75 | GameObjectNameAsPrefabChild = gameObjectName; 76 | } 77 | 78 | public float GetHeight() 79 | { 80 | int numAdditionalLines = 0; 81 | if (PrefabContainer != null) 82 | { 83 | ++numAdditionalLines; 84 | } 85 | return DependencyViewerGraphDrawer.NodeHeight + numAdditionalLines * EditorGUIUtility.singleLineHeight; 86 | } 87 | 88 | public float GetWidth() 89 | { 90 | return DependencyViewerGraphDrawer.NodeWidth; 91 | } 92 | 93 | public Vector2 GetSize() 94 | { 95 | return new Vector2(GetWidth(), GetHeight()); 96 | } 97 | 98 | public Vector2 GetLeftInputAnchorPosition() 99 | { 100 | return new Vector2(_position.x, _position.y + GetHeight() / 2); 101 | } 102 | 103 | public Vector2 GetRightInputAnchorPosition() 104 | { 105 | return new Vector2(_position.x + GetWidth(), _position.y + GetHeight() / 2); 106 | } 107 | 108 | public void SetPositionX(float x) 109 | { 110 | _position.x = x; 111 | } 112 | 113 | public void SetPositionY(float y) 114 | { 115 | _position.y = y; 116 | } 117 | 118 | public List GetInputNodesFromSide(NodeInputSide side) 119 | { 120 | return side == NodeInputSide.Left ? _leftInputs : _rightInputs; 121 | } 122 | 123 | public DependencyViewerNode GetParent(NodeInputSide treeSide) 124 | { 125 | var parentList = (treeSide == NodeInputSide.Left ? _rightInputs : _leftInputs); 126 | return (parentList.Count > 0 ? parentList[0] : null); 127 | } 128 | 129 | public List GetChildren(NodeInputSide treeSide) 130 | { 131 | return GetInputNodesFromSide(treeSide); 132 | } 133 | 134 | public int GetSiblingIndex(NodeInputSide treeSide) 135 | { 136 | var parentNode = GetParent(treeSide); 137 | if (parentNode == null) 138 | { 139 | return 0; 140 | } 141 | 142 | var siblings = parentNode.GetChildren(treeSide); 143 | for (int siblingIdx = 0; siblingIdx < siblings.Count; ++siblingIdx) 144 | { 145 | if (siblings[siblingIdx] == this) 146 | { 147 | return siblingIdx; 148 | } 149 | } 150 | return -1; 151 | } 152 | 153 | public DependencyViewerNode GetFirstSibling(NodeInputSide treeSide) 154 | { 155 | var parent = GetParent(treeSide); 156 | if (parent == null) 157 | { 158 | return this; 159 | } 160 | 161 | var childNodes = parent.GetChildren(treeSide); 162 | return (childNodes.Count > 0 ? childNodes[0] : null); 163 | } 164 | 165 | public DependencyViewerNode GetLastSibling(NodeInputSide treeSide) 166 | { 167 | var parent = GetParent(treeSide); 168 | if (parent == null) 169 | { 170 | return this; 171 | } 172 | 173 | var childNodes = parent.GetChildren(treeSide); 174 | return (childNodes.Count > 0 ? childNodes[childNodes.Count - 1] : null); 175 | } 176 | 177 | public DependencyViewerNode GetFirstChild(NodeInputSide treeSide) 178 | { 179 | var childNodes = GetChildren(treeSide); 180 | return (childNodes.Count > 0 ? childNodes[0] : null); 181 | } 182 | 183 | public DependencyViewerNode GetLastChild(NodeInputSide treeSide) 184 | { 185 | var childNodes = GetChildren(treeSide); 186 | return (childNodes.Count > 0 ? childNodes[childNodes.Count - 1] : null); 187 | } 188 | 189 | public DependencyViewerNode GetPreviousSibling(NodeInputSide treeSide) 190 | { 191 | var parent = GetParent(treeSide); 192 | if (parent == null) 193 | { 194 | return null; 195 | } 196 | 197 | var childNodes = parent.GetChildren(treeSide); 198 | int childIdx = GetSiblingIndex(treeSide); 199 | return (childIdx > 0 ? childNodes[childIdx - 1] : null); 200 | } 201 | 202 | public DependencyViewerNode GetNextSibling(NodeInputSide treeSide) 203 | { 204 | var parent = GetParent(treeSide); 205 | if (parent == null) 206 | { 207 | return null; 208 | } 209 | 210 | var childNodes = parent.GetChildren(treeSide); 211 | int childIdx = GetSiblingIndex(treeSide); 212 | return (childIdx + 1 < childNodes.Count ? childNodes[childIdx + 1] : null); 213 | } 214 | 215 | public bool IsLeaf(NodeInputSide treeSide) 216 | { 217 | return (GetNumChildren(treeSide) == 0); 218 | } 219 | 220 | public bool IsFirstSibling(NodeInputSide treeSide) 221 | { 222 | return GetSiblingIndex(treeSide) == 0; 223 | } 224 | 225 | public int GetNumChildren(NodeInputSide treeSide) 226 | { 227 | return GetChildren(treeSide).Count; 228 | } 229 | 230 | public void ForeachChildrenRecursively(NodeInputSide treeSide, Action onEachNodeCallback) 231 | { 232 | ForeachChildrenRecursively(treeSide, this, onEachNodeCallback); 233 | } 234 | 235 | private void ForeachChildrenRecursively(NodeInputSide treeSide, DependencyViewerNode node, Action onEachNodeCallback) 236 | { 237 | var children = node.GetChildren(treeSide); 238 | for (int i = 0; i < children.Count; ++i) 239 | { 240 | ForeachChildrenRecursively(treeSide, children[i], onEachNodeCallback); 241 | } 242 | 243 | onEachNodeCallback(node); 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4f647e1b461c08844acb296d2df053a5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | using UnityEditor; 6 | 7 | internal class DependencyViewerSettings : ScriptableObject 8 | { 9 | private const string DependencyViewerSettingsSaveName = "DependencyViewerSettings"; 10 | 11 | public event Action onSettingsChanged; 12 | 13 | [Flags] 14 | public enum ObjectType 15 | { 16 | ScriptableObject = 0x01, 17 | Component = 0x02, 18 | MonoScript = 0x04 19 | } 20 | 21 | public enum SceneSearchMode 22 | { 23 | NoSearch, 24 | SearchOnlyInCurrentScene, 25 | SearchEverywhere 26 | } 27 | 28 | 29 | [Header("References")] 30 | 31 | [SerializeField] 32 | [Tooltip("If checked, the references will be searched")] 33 | private bool _findReferences = true; 34 | public bool FindReferences 35 | { 36 | get { return _findReferences; } 37 | set { _findReferences = value; } 38 | } 39 | 40 | [SerializeField] 41 | [Tooltip("Filters when browsing project files for asset referencing")] 42 | private string _excludeAssetFilters = ".dll,.a,.so,.asmdef,.aar,.bundle,.jar"; 43 | public string ExcludeAssetFilters 44 | { 45 | get { return _excludeAssetFilters; } 46 | set { _excludeAssetFilters = value; } 47 | } 48 | 49 | [SerializeField] 50 | [Tooltip("If set, only these directories will be browsed for references. Can really improve search speed.")] 51 | private string[] _referencesAssetsDirectories; 52 | public string[] ReferencesAssetDirectories 53 | { 54 | get { return _referencesAssetsDirectories; } 55 | set { _referencesAssetsDirectories = value; } 56 | } 57 | 58 | [SerializeField] 59 | private SceneSearchMode _sceneSearchType = SceneSearchMode.SearchEverywhere; 60 | public SceneSearchMode SceneSearchType 61 | { 62 | get { return _sceneSearchType; } 63 | set { _sceneSearchType = value; } 64 | } 65 | 66 | 67 | [Header("Dependencies")] 68 | 69 | [SerializeField] 70 | [Tooltip("If checked, the dependencies will be searched")] 71 | private bool _findDependencies = true; 72 | public bool FindDependencies 73 | { 74 | get { return _findDependencies; } 75 | set { _findDependencies = value; } 76 | } 77 | 78 | [SerializeField] 79 | [Tooltip("Defines the depth of the search among the dependencies")] 80 | private int _dependenciesDepth = 1; 81 | public int DependenciesDepth 82 | { 83 | get { return _dependenciesDepth; } 84 | set { _dependenciesDepth = value; } 85 | } 86 | 87 | 88 | [Header("Common")] 89 | 90 | [SerializeField] 91 | [EnumFlags] 92 | [Tooltip("Defines the object types to analyze")] 93 | private ObjectType _objectTypesFilter = (ObjectType) 0xFFFF; 94 | public ObjectType ObjectTypesFilter 95 | { 96 | get { return _objectTypesFilter; } 97 | set { _objectTypesFilter = value; } 98 | } 99 | 100 | 101 | public static DependencyViewerSettings Create() 102 | { 103 | DependencyViewerSettings settings = ScriptableObject.CreateInstance(); 104 | settings.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy; 105 | return settings; 106 | } 107 | 108 | public void Save() 109 | { 110 | var data = EditorJsonUtility.ToJson(this, false); 111 | EditorPrefs.SetString(DependencyViewerSettingsSaveName, data); 112 | } 113 | 114 | public void Load() 115 | { 116 | if (EditorPrefs.HasKey(DependencyViewerSettingsSaveName)) 117 | { 118 | var data = EditorPrefs.GetString(DependencyViewerSettingsSaveName); 119 | EditorJsonUtility.FromJsonOverwrite(data, this); 120 | } 121 | } 122 | 123 | public bool CanObjectTypeBeIncluded(UnityEngine.Object obj) 124 | { 125 | if ((ObjectTypesFilter & ObjectType.ScriptableObject) == 0 && 126 | obj is ScriptableObject) 127 | { 128 | return false; 129 | } 130 | 131 | if ((ObjectTypesFilter & ObjectType.Component) == 0 && 132 | obj is Component) 133 | { 134 | return false; 135 | } 136 | 137 | if ((ObjectTypesFilter & ObjectType.MonoScript) == 0 && 138 | obj is MonoScript) 139 | { 140 | return false; 141 | } 142 | 143 | return true; 144 | } 145 | 146 | void OnValidate() 147 | { 148 | if (onSettingsChanged != null) 149 | { 150 | onSettingsChanged.Invoke(); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 51e495af0de401948b47301d6df5e744 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerSettingsOverlay.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using System; 6 | 7 | internal class DependencyViewerSettingsOverlay 8 | { 9 | private static readonly Rect OverlayRect = new Rect(10, 10, 120, EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing * 3); 10 | private DependencyViewerSettings _settings; 11 | 12 | public DependencyViewerSettingsOverlay(DependencyViewerSettings settings) 13 | { 14 | _settings = settings; 15 | } 16 | 17 | public void Draw() 18 | { 19 | if (GUI.Button(OverlayRect, "Open Settings...")) 20 | { 21 | Selection.activeObject = _settings; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerSettingsOverlay.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a9f53600d1d0456429f16bf1219d2f97 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerStatusBar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | internal class DependencyViewerStatusBar 8 | { 9 | private static readonly float StatusBarHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing * 2; 10 | private static readonly Vector2 StatusBarMargin = new Vector2(5, 5); 11 | private static readonly Vector2 StatusBarPadding = new Vector2(2, 2); 12 | 13 | private string _statusText; 14 | 15 | public void SetText(string newText) 16 | { 17 | _statusText = newText; 18 | } 19 | 20 | public void ClearText() 21 | { 22 | SetText(string.Empty); 23 | } 24 | 25 | public void Draw(Rect windowPosition) 26 | { 27 | Rect statusBarRect = 28 | new Rect(StatusBarMargin.x, windowPosition.height - (StatusBarHeight + StatusBarMargin.y), 29 | windowPosition.width - StatusBarMargin.x * 2, StatusBarHeight); 30 | 31 | GUI.Box(statusBarRect, GUIContent.none); 32 | 33 | Rect statusBarContentRect = 34 | new Rect(statusBarRect.x + StatusBarPadding.x, statusBarRect.y + StatusBarPadding.y, 35 | statusBarRect.width - StatusBarPadding.x * 2, statusBarRect.height - StatusBarPadding.y * 2); 36 | 37 | GUI.Label(statusBarContentRect, _statusText); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerStatusBar.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec57191b97e1b7d4f9e46e13cb9270fb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | using UnityEngine.SceneManagement; 6 | 7 | internal static class DependencyViewerUtility 8 | { 9 | public static List GetCurrentOpenedScenes() 10 | { 11 | List scenes = new List(); 12 | for (int sceneIdx = 0; sceneIdx < SceneManager.sceneCount; ++sceneIdx) 13 | { 14 | Scene scene = SceneManager.GetSceneAt(sceneIdx); 15 | scenes.Add(scene); 16 | } 17 | return scenes; 18 | } 19 | 20 | public static void ForeachGameObjectInScenes(List scenes, bool visitChildren, Action callback) 21 | { 22 | for (int i = 0; i < scenes.Count; ++i) 23 | { 24 | ForeachGameObjectInScene(scenes[i], visitChildren, callback); 25 | } 26 | } 27 | 28 | public static void ForeachGameObjectInScene(Scene scene, bool visitChildren, Action callback) 29 | { 30 | GameObject[] gameObjects = scene.GetRootGameObjects(); 31 | for (int gameObjectIdx = 0; gameObjectIdx < gameObjects.Length; ++gameObjectIdx) 32 | { 33 | GameObject rootGameObject = gameObjects[gameObjectIdx]; 34 | callback(rootGameObject); 35 | if (visitChildren) 36 | { 37 | UDGV.GameObjectUtility.ForeachChildrenGameObject(rootGameObject, callback); 38 | } 39 | } 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Editor/Viewer/DependencyViewerUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40aa5b260032b3a44a80421e89a16d73 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2019 Extend Reality Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6d73d5689879dd94990c80c1ff0b3737 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Medias~/Screenshot01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Begounet/unity-dependency-graph-viewer/ce80b0a47d0fc3e76acaf146e8cc3a75333b5537/Medias~/Screenshot01.jpg -------------------------------------------------------------------------------- /Medias~/Screenshot02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Begounet/unity-dependency-graph-viewer/ce80b0a47d0fc3e76acaf146e8cc3a75333b5537/Medias~/Screenshot02.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Dependency Graph Viewer 2 | Visual graph in editor to see dependencies/references of an asset on Unity (based on UE4 reference viewer) 3 | 4 | # "Roadmap" 5 | * New cache system for fast search: 6 | 7 | * Find references/dependencies on common assets: OK 8 | * Find references/dependencies on prefabs: OK 9 | * Find references/dependencies on scenes (without loading the scene): OK 10 | * Build all sync and async (with operation status): OK 11 | * Build one Object only: OK 12 | * Watch file changes and rebuild only these files: In Progress 13 | * Save/load of cache (JSON into EditorPrefs): Waiting 14 | * Put namespace everywhere: Waiting 15 | * Couple cache system with the node tree: Waiting 16 | * Remove old system: Waiting 17 | * Optimization of Unity's common assets (not browse all properties): Waiting 18 | * Find references/dependencies on UnityEvents: Waiting 19 | * Optimization of the overall search by parsing file instead of loading objects (need performance tests): Waiting 20 | * Find references/dependencies on Animation/Animator/Timeline assets: Waiting 21 | 22 | * UnityEvent Method Search: 23 | 24 | * Find GameObjects using UnityEvents from a method name: Waiting 25 | 26 | 27 | 28 | # How to 29 | Just select a GameObject or any asset in the Project window, right click > View dependencies. 30 | Once the window is opened, you can navigate between dependencies by clicking on the little arrow on each node. 31 | 32 | # Screenshots 33 | ![Access menu](Medias~/Screenshot01.jpg) 34 | ![Dependency Graph Viewer](Medias~/Screenshot02.jpg) -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 01ef22af75dae4640b95cd7595eaf6e9 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------