├── LICENSE.md
├── .gitattributes
├── Assets~
├── icons.png
├── lines.png
├── lines.png.meta
├── difference.png
└── multi_prefab.gif
├── Editor
├── ObjectIcon.cs.meta
├── CoreHierarchyPass.cs.meta
├── PreferencesWindow.cs.meta
├── MultiObjectPrefabSupport.cs.meta
├── com.nomnom.hierarchy-window-extensions.Editor.asmdef.meta
├── ObjectConnector.cs.meta
├── com.nomnom.hierarchy-window-extensions.Editor.asmdef
├── ObjectIcon.cs
├── MultiObjectPrefabSupport.cs
├── CoreHierarchyPass.cs
├── PreferencesWindow.cs
└── ObjectConnector.cs
├── Resources
├── Dashed_Line.png
├── Connector_Line.png
├── Connector_End_Line.png
├── Icon_Mat.mat.meta
├── Dashed_Line_Mat.mat.meta
├── Icon_Mat.mat
├── Dashed_Line_Mat.mat
├── Dashed_Line.png.meta
├── Connector_Line.png.meta
└── Connector_End_Line.png.meta
├── LICENSE.md.meta
├── README.md.meta
├── package.json.meta
├── Editor.meta
├── Resources.meta
├── .gitignore
├── package.json
├── .github
└── workflows
│ └── main.yml
└── README.md
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/Assets~/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Assets~/icons.png
--------------------------------------------------------------------------------
/Assets~/lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Assets~/lines.png
--------------------------------------------------------------------------------
/Assets~/lines.png.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f875eb3811ac45f99567b4ac8fdb82d5
3 | timeCreated: 1641418906
--------------------------------------------------------------------------------
/Assets~/difference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Assets~/difference.png
--------------------------------------------------------------------------------
/Editor/ObjectIcon.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 49517792a0794b28ac0cfb3bfe43da48
3 | timeCreated: 1641401781
--------------------------------------------------------------------------------
/Assets~/multi_prefab.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Assets~/multi_prefab.gif
--------------------------------------------------------------------------------
/Editor/CoreHierarchyPass.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 00fb729823db4dae873474621cdfc6fa
3 | timeCreated: 1641398670
--------------------------------------------------------------------------------
/Editor/PreferencesWindow.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0a7da73d6ad54abe87148744eadcf029
3 | timeCreated: 1641407798
--------------------------------------------------------------------------------
/Resources/Dashed_Line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Resources/Dashed_Line.png
--------------------------------------------------------------------------------
/Resources/Connector_Line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Resources/Connector_Line.png
--------------------------------------------------------------------------------
/Editor/MultiObjectPrefabSupport.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6efedc1e3dd642b5a86fed9e4742be23
3 | timeCreated: 1641420435
--------------------------------------------------------------------------------
/Resources/Connector_End_Line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nomnomab/Hierarchy-Window-Extensions/HEAD/Resources/Connector_End_Line.png
--------------------------------------------------------------------------------
/LICENSE.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fd56807b6d170bc44b7678eb3ec7b3ca
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0b3cc64c3cd31354488c70e1cf71a47e
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 74f05093160b8774c9be17879f7d0322
3 | PackageManifestImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a277ab1a60427f94482c1bfbe96c8fe9
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Resources.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d77e0e783b9830445bd5133c5c9bce34
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Resources/Icon_Mat.mat.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8b8277a20fa3c764fb91886665e41cb5
3 | NativeFormatImporter:
4 | externalObjects: {}
5 | mainObjectFileID: 2100000
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/com.nomnom.hierarchy-window-extensions.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3e9fb233a633c9e4ba476ca4461cbdb0
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Resources/Dashed_Line_Mat.mat.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f32981495e6e1994bba5e966a60e741d
3 | NativeFormatImporter:
4 | externalObjects: {}
5 | mainObjectFileID: 2100000
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/ObjectConnector.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a5ba9e85c09d24c4494290f697c78549
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Ll]ibrary/
2 | [Tt]emp/
3 | [Oo]bj/
4 | [Bb]uild/
5 | [Bb]uilds/
6 | Assets/AssetStoreTools*
7 |
8 | # Visual Studio cache directory
9 | .vs/
10 |
11 | # Autogenerated VS/MD/Consulo solution and project files
12 | ExportedObj/
13 | .consulo/
14 | *.csproj
15 | *.unityproj
16 | *.sln
17 | *.suo
18 | *.tmp
19 | *.user
20 | *.userprefs
21 | *.pidb
22 | *.booproj
23 | *.svd
24 | *.pdb
25 | *.opendb
26 | *.VC.db
27 |
28 | # Unity3D generated meta files
29 | *.pidb.meta
30 | *.pdb.meta
31 |
32 | # Unity3D Generated File On Crash Reports
33 | sysinfo.txt
34 |
35 | # Builds
36 | *.apk
37 | *.unitypackage
38 |
--------------------------------------------------------------------------------
/Editor/com.nomnom.hierarchy-window-extensions.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.nomnom.hierarchy-window-extensions.Editor",
3 | "rootNamespace": "Nomnom.HierarchyWindowExtensions",
4 | "references": [
5 | "com.nomnom.easier-custom-preferences.Editor"
6 | ],
7 | "includePlatforms": [
8 | "Editor"
9 | ],
10 | "excludePlatforms": [],
11 | "allowUnsafeCode": false,
12 | "overrideReferences": false,
13 | "precompiledReferences": [],
14 | "autoReferenced": true,
15 | "defineConstraints": [],
16 | "versionDefines": [],
17 | "noEngineReferences": false
18 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.nomnom.hierarchy-window-extensions",
3 | "version": "1.1.7",
4 | "displayName": "Hierarchy Window Extensions",
5 | "description": "This aims to improve the usability of the hierarchy window.",
6 | "unity": "2020.3",
7 | "unityRelease": "20f1",
8 | "licensesUrl": "https://choosealicense.com/licenses/mit/",
9 | "dependencies": {
10 | "com.nomnom.easier-custom-preferences": "1.1.2"
11 | },
12 | "devDependencies": {},
13 | "samples": [],
14 | "keywords": [
15 | "nomnom",
16 | "hierarchy",
17 | "window",
18 | "tool"
19 | ],
20 | "author": {
21 | "name": "Andrew Burke",
22 | "email": "",
23 | "url": ""
24 | },
25 | "type": "library"
26 | }
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | on: push
2 |
3 | name: Create release
4 |
5 | jobs:
6 | build:
7 | name: Create release
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout code
11 | uses: actions/checkout@master
12 |
13 | - name: Extract version
14 | id: extract_version
15 | uses: Saionaro/extract-package-version@v1.0.6
16 | - name: Print version
17 | run: echo ${{ steps.extract_version.outputs.version }}
18 | - name: Create Release
19 | id: create_release
20 | uses: actions/create-release@v1
21 | env:
22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
23 | with:
24 | tag_name: v${{ steps.extract_version.outputs.version }}
25 | release_name: v${{ steps.extract_version.outputs.version }}
26 | draft: false
27 | prerelease: false
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hierarchy Window Extensions
2 | This aims to improve the usability of the hierarchy window.
3 |
4 | 
5 |
6 | ## Installation
7 | - OpenUPM
8 | - `openupm add com.nomnom.hierarchy-window-extensions`
9 | - Package Manager
10 | - Add through git url `https://github.com/nomnomab/Hierarchy-Window-Extensions.git`
11 |
12 | ### Package Settings
13 | - Parts of this package can be enabled/disabled via the preferences menu, located in `Edit/Preferences/Hierarchy Window Extensions`
14 |
15 | ## Current Enhancements
16 | #### Custom Lines
17 | 
18 |
19 | #### Object Aware Icons
20 | 
21 | - The first-most component on an object will take priority
22 | - If the object only has a single component, the transform is shown
23 | - If it has more than a single component, the next component will be shown
24 | - Canvas renderer components are ignored for UI so the elements can be seen more clearly
25 |
26 | #### Multi-Object Prefab Creation
27 | 
28 | - Select multiple scene objects, right-click, and select `Prefab/Multi-Prefab` to select a folder for the prefabs to be placed into
--------------------------------------------------------------------------------
/Editor/ObjectIcon.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEditor;
3 | using UnityEditor.IMGUI.Controls;
4 | using UnityEngine;
5 |
6 | namespace Nomnom.HierarchyWindowExtensions.Editor {
7 | ///
8 | /// Replaces the default "cube" icon on GameObjects with their highest order
9 | /// component.
10 | ///
11 | internal static class ObjectIcon {
12 | private static Dictionary _components;
13 |
14 | [InitializeOnLoadMethod]
15 | private static void OnLoad() {
16 | _components = new Dictionary();
17 |
18 | EditorApplication.hierarchyChanged += OnHierarchyChanged;
19 |
20 | OnHierarchyChanged();
21 | }
22 |
23 | private static void OnHierarchyChanged() {
24 | _components.Clear();
25 |
26 | GameObject[] objects = Object.FindObjectsOfType();
27 | foreach (GameObject gameObject in objects) {
28 | Component[] components = gameObject.GetComponents();
29 | Component toUse = components.Length > 1 ? components[1] : components[0];
30 |
31 | if (toUse is CanvasRenderer && components.Length > 2) {
32 | toUse = components[2];
33 | }
34 |
35 | Texture newIcon = EditorGUIUtility.ObjectContent(null, toUse.GetType()).image;
36 |
37 | if (newIcon == null) {
38 | // probably script
39 | newIcon = EditorGUIUtility.ObjectContent(toUse, toUse.GetType()).image;
40 | }
41 |
42 | _components.Add(gameObject, newIcon);
43 | }
44 | }
45 |
46 | public static void Draw(TreeViewItem item, Event e, int instanceId, in Rect rect) {
47 | Object obj = EditorUtility.InstanceIDToObject(instanceId);
48 | if (!(obj is GameObject gameObject)) {
49 | return;
50 | }
51 |
52 | // get the first component for now
53 | if (!_components.TryGetValue(gameObject, out Texture texture)) {
54 | return;
55 | }
56 |
57 | if (item == null) {
58 | return;
59 | }
60 |
61 | item.icon = (Texture2D)texture;
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/Editor/MultiObjectPrefabSupport.cs:
--------------------------------------------------------------------------------
1 | #if NOM_HIERARCHY_PREFAB
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using UnityEditor;
6 | using UnityEngine;
7 |
8 | namespace Nomnom.HierarchyWindowExtensions.Editor {
9 | internal static class MultiObjectPrefabSupport {
10 | private static List _objects;
11 | private static string _directory;
12 |
13 | [MenuItem("GameObject/Prefab/Multi-Prefab", false, 0)]
14 | private static void MakePrefab() {
15 | if (_objects == null) {
16 | _objects = new List();
17 |
18 | GameObject[] tmpObjects = Selection.gameObjects;
19 |
20 | string directory = EditorUtility.OpenFolderPanel("Open Folder", "Assets/", string.Empty);
21 | string assetsPath = Application.dataPath;
22 |
23 | if (assetsPath.Length > directory.Length || string.IsNullOrEmpty(directory)) {
24 | Debug.LogError("You selected an invalid folder");
25 | } else {
26 | _directory = directory;
27 | }
28 |
29 | // only use objects without parent selectors
30 | for (int i = 0; i < tmpObjects.Length; i++) {
31 | GameObject gameObject = tmpObjects[i];
32 | Transform currentTransform = gameObject.transform;
33 | bool isValid = true;
34 |
35 | Transform parent = currentTransform.parent;
36 | while (parent) {
37 | if (tmpObjects.Contains(parent.gameObject)) {
38 | isValid = false;
39 | }
40 |
41 | parent = parent.parent;
42 | }
43 |
44 | if (isValid) {
45 | _objects.Add(gameObject);
46 | }
47 | }
48 | }
49 |
50 | GameObject obj = _objects[0];
51 |
52 | if (!string.IsNullOrEmpty(_directory)) {
53 | PrefabUtility.SaveAsPrefabAssetAndConnect(obj, $"{_directory}/{obj.name}.prefab", InteractionMode.UserAction);
54 | }
55 |
56 | _objects.RemoveAt(0);
57 |
58 | if (_objects.Count == 0) {
59 | _objects = null;
60 | _directory = null;
61 | }
62 | }
63 |
64 | [MenuItem("GameObject/Prefab/Multi-Prefab", true)]
65 | private static bool DoThingValidate() {
66 | return Selection.gameObjects != null && Selection.gameObjects.Length > 1;
67 | }
68 | }
69 | }
70 | #endif
--------------------------------------------------------------------------------
/Editor/CoreHierarchyPass.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using UnityEditor;
4 | using UnityEditor.IMGUI.Controls;
5 | using UnityEngine;
6 | using Object = UnityEngine.Object;
7 |
8 | namespace Nomnom.HierarchyWindowExtensions.Editor {
9 | internal static class CoreHierarchyPass {
10 | private static readonly Type _sceneHierarchyWindowType = Type.GetType(
11 | "UnityEditor.SceneHierarchyWindow, UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
12 | private static readonly PropertyInfo _lastInteractedHierarchyWindow = _sceneHierarchyWindowType
13 | .GetProperty("lastInteractedHierarchyWindow", BindingFlags.Public | BindingFlags.Static);
14 |
15 | private static object _treeView;
16 | private static MethodInfo _findItem;
17 | private static MethodInfo _initTree;
18 | private static Object _lastSelection;
19 |
20 | [InitializeOnLoadMethod]
21 | private static void OnLoad() {
22 | EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
23 | }
24 |
25 | private static void HierarchyWindowItemOnGUI(int instanceId, Rect rect) {
26 | if (_treeView == null) {
27 | AssignTreeView();
28 | }
29 |
30 | if (PreferencesWindow.UseCustomLines) {
31 | ObjectConnector.Draw(instanceId, rect);
32 | }
33 |
34 | if (PreferencesWindow.UseCustomIcons) {
35 | Event e = Event.current;
36 | TreeViewItem item = GetItem(instanceId);
37 |
38 | ObjectIcon.Draw(item, e, instanceId, rect);
39 | }
40 | }
41 |
42 | public static void ResetTree() {
43 | object lastWindow = _lastInteractedHierarchyWindow.GetValue(null);
44 | object sceneHierarchy = lastWindow
45 | .GetType()
46 | .GetField("m_SceneHierarchy", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(lastWindow);
47 | _initTree.Invoke(sceneHierarchy, null);
48 |
49 | EditorApplication.RepaintHierarchyWindow();
50 | }
51 |
52 | private static TreeViewItem GetItem(int id) {
53 | return (TreeViewItem)_findItem?.Invoke(_treeView, new object[] { id });
54 | }
55 |
56 | private static void AssignTreeView() {
57 | object lastWindow = _lastInteractedHierarchyWindow.GetValue(null);
58 | object sceneHierarchy = lastWindow
59 | .GetType()
60 | .GetField("m_SceneHierarchy", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(lastWindow);
61 | _treeView = sceneHierarchy.GetType()
62 | .GetField("m_TreeView", BindingFlags.NonPublic | BindingFlags.Instance)
63 | .GetValue(sceneHierarchy);
64 | _findItem = _treeView.GetType().GetMethod("FindItem", BindingFlags.Public | BindingFlags.Instance);
65 | _initTree = sceneHierarchy.GetType()
66 | .GetMethod("Init", BindingFlags.NonPublic | BindingFlags.Instance);
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/Resources/Icon_Mat.mat:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!21 &2100000
4 | Material:
5 | serializedVersion: 6
6 | m_ObjectHideFlags: 0
7 | m_CorrespondingSourceObject: {fileID: 0}
8 | m_PrefabInstance: {fileID: 0}
9 | m_PrefabAsset: {fileID: 0}
10 | m_Name: Icon_Mat
11 | m_Shader: {fileID: 10760, guid: 0000000000000000f000000000000000, type: 0}
12 | m_ShaderKeywords: _ALPHATEST_ON
13 | m_LightmapFlags: 4
14 | m_EnableInstancingVariants: 0
15 | m_DoubleSidedGI: 0
16 | m_CustomRenderQueue: -1
17 | stringTagMap: {}
18 | disabledShaderPasses: []
19 | m_SavedProperties:
20 | serializedVersion: 3
21 | m_TexEnvs:
22 | - _BumpMap:
23 | m_Texture: {fileID: 0}
24 | m_Scale: {x: 1, y: 1}
25 | m_Offset: {x: 0, y: 0}
26 | - _DetailAlbedoMap:
27 | m_Texture: {fileID: 0}
28 | m_Scale: {x: 1, y: 1}
29 | m_Offset: {x: 0, y: 0}
30 | - _DetailMask:
31 | m_Texture: {fileID: 0}
32 | m_Scale: {x: 1, y: 1}
33 | m_Offset: {x: 0, y: 0}
34 | - _DetailNormalMap:
35 | m_Texture: {fileID: 0}
36 | m_Scale: {x: 1, y: 1}
37 | m_Offset: {x: 0, y: 0}
38 | - _DetailTex:
39 | m_Texture: {fileID: 2800000, guid: dac76d2aa88d3e54fa6d488fe429be9b, type: 3}
40 | m_Scale: {x: 1, y: 1}
41 | m_Offset: {x: 0, y: 0}
42 | - _EmissionMap:
43 | m_Texture: {fileID: 0}
44 | m_Scale: {x: 1, y: 1}
45 | m_Offset: {x: 0, y: 0}
46 | - _MainTex:
47 | m_Texture: {fileID: 0}
48 | m_Scale: {x: 1, y: 1}
49 | m_Offset: {x: 0, y: 0}
50 | - _MetallicGlossMap:
51 | m_Texture: {fileID: 0}
52 | m_Scale: {x: 1, y: 1}
53 | m_Offset: {x: 0, y: 0}
54 | - _OcclusionMap:
55 | m_Texture: {fileID: 0}
56 | m_Scale: {x: 1, y: 1}
57 | m_Offset: {x: 0, y: 0}
58 | - _ParallaxMap:
59 | m_Texture: {fileID: 0}
60 | m_Scale: {x: 1, y: 1}
61 | m_Offset: {x: 0, y: 0}
62 | m_Floats:
63 | - _BumpScale: 1
64 | - _ColorMask: 15
65 | - _Cutoff: 0.5
66 | - _DetailNormalMapScale: 1
67 | - _DstBlend: 0
68 | - _GlossMapScale: 1
69 | - _Glossiness: 0.5
70 | - _GlossyReflections: 1
71 | - _Metallic: 0
72 | - _Mode: 1
73 | - _OcclusionStrength: 1
74 | - _Parallax: 0.02
75 | - _SmoothnessTextureChannel: 0
76 | - _SpecularHighlights: 1
77 | - _SrcBlend: 1
78 | - _Stencil: 0
79 | - _StencilComp: 8
80 | - _StencilOp: 0
81 | - _StencilReadMask: 255
82 | - _StencilWriteMask: 255
83 | - _Strength: 0.2
84 | - _UVSec: 0
85 | - _UseUIAlphaClip: 0
86 | - _ZWrite: 1
87 | m_Colors:
88 | - _Color: {r: 1, g: 1, b: 1, a: 1}
89 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
90 | m_BuildTextureStacks: []
91 |
--------------------------------------------------------------------------------
/Resources/Dashed_Line_Mat.mat:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!21 &2100000
4 | Material:
5 | serializedVersion: 6
6 | m_ObjectHideFlags: 0
7 | m_CorrespondingSourceObject: {fileID: 0}
8 | m_PrefabInstance: {fileID: 0}
9 | m_PrefabAsset: {fileID: 0}
10 | m_Name: Dashed_Line_Mat
11 | m_Shader: {fileID: 10760, guid: 0000000000000000f000000000000000, type: 0}
12 | m_ShaderKeywords: _ALPHATEST_ON
13 | m_LightmapFlags: 4
14 | m_EnableInstancingVariants: 0
15 | m_DoubleSidedGI: 0
16 | m_CustomRenderQueue: -1
17 | stringTagMap: {}
18 | disabledShaderPasses: []
19 | m_SavedProperties:
20 | serializedVersion: 3
21 | m_TexEnvs:
22 | - _BumpMap:
23 | m_Texture: {fileID: 0}
24 | m_Scale: {x: 1, y: 1}
25 | m_Offset: {x: 0, y: 0}
26 | - _DetailAlbedoMap:
27 | m_Texture: {fileID: 0}
28 | m_Scale: {x: 1, y: 1}
29 | m_Offset: {x: 0, y: 0}
30 | - _DetailMask:
31 | m_Texture: {fileID: 0}
32 | m_Scale: {x: 1, y: 1}
33 | m_Offset: {x: 0, y: 0}
34 | - _DetailNormalMap:
35 | m_Texture: {fileID: 0}
36 | m_Scale: {x: 1, y: 1}
37 | m_Offset: {x: 0, y: 0}
38 | - _DetailTex:
39 | m_Texture: {fileID: 2800000, guid: dac76d2aa88d3e54fa6d488fe429be9b, type: 3}
40 | m_Scale: {x: 1, y: 1}
41 | m_Offset: {x: 0, y: 0}
42 | - _EmissionMap:
43 | m_Texture: {fileID: 0}
44 | m_Scale: {x: 1, y: 1}
45 | m_Offset: {x: 0, y: 0}
46 | - _MainTex:
47 | m_Texture: {fileID: 0}
48 | m_Scale: {x: 1, y: 1}
49 | m_Offset: {x: 0, y: 0}
50 | - _MetallicGlossMap:
51 | m_Texture: {fileID: 0}
52 | m_Scale: {x: 1, y: 1}
53 | m_Offset: {x: 0, y: 0}
54 | - _OcclusionMap:
55 | m_Texture: {fileID: 0}
56 | m_Scale: {x: 1, y: 1}
57 | m_Offset: {x: 0, y: 0}
58 | - _ParallaxMap:
59 | m_Texture: {fileID: 0}
60 | m_Scale: {x: 1, y: 1}
61 | m_Offset: {x: 0, y: 0}
62 | m_Floats:
63 | - _BumpScale: 1
64 | - _ColorMask: 15
65 | - _Cutoff: 0.5
66 | - _DetailNormalMapScale: 1
67 | - _DstBlend: 0
68 | - _GlossMapScale: 1
69 | - _Glossiness: 0.5
70 | - _GlossyReflections: 1
71 | - _Metallic: 0
72 | - _Mode: 1
73 | - _OcclusionStrength: 1
74 | - _Parallax: 0.02
75 | - _SmoothnessTextureChannel: 0
76 | - _SpecularHighlights: 1
77 | - _SrcBlend: 1
78 | - _Stencil: 0
79 | - _StencilComp: 8
80 | - _StencilOp: 0
81 | - _StencilReadMask: 255
82 | - _StencilWriteMask: 255
83 | - _Strength: 0.2
84 | - _UVSec: 0
85 | - _UseUIAlphaClip: 0
86 | - _ZWrite: 1
87 | m_Colors:
88 | - _Color: {r: 1, g: 1, b: 1, a: 0.5019608}
89 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
90 | m_BuildTextureStacks: []
91 |
--------------------------------------------------------------------------------
/Resources/Dashed_Line.png.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dac76d2aa88d3e54fa6d488fe429be9b
3 | TextureImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 11
7 | mipmaps:
8 | mipMapMode: 0
9 | enableMipMap: 1
10 | sRGBTexture: 1
11 | linearTexture: 0
12 | fadeOut: 0
13 | borderMipMap: 0
14 | mipMapsPreserveCoverage: 0
15 | alphaTestReferenceValue: 0.5
16 | mipMapFadeDistanceStart: 1
17 | mipMapFadeDistanceEnd: 3
18 | bumpmap:
19 | convertToNormalMap: 0
20 | externalNormalMap: 0
21 | heightScale: 0.25
22 | normalMapFilter: 0
23 | isReadable: 0
24 | streamingMipmaps: 0
25 | streamingMipmapsPriority: 0
26 | vTOnly: 0
27 | grayScaleToAlpha: 0
28 | generateCubemap: 6
29 | cubemapConvolution: 0
30 | seamlessCubemap: 0
31 | textureFormat: 1
32 | maxTextureSize: 2048
33 | textureSettings:
34 | serializedVersion: 2
35 | filterMode: 0
36 | aniso: 1
37 | mipBias: 0
38 | wrapU: 1
39 | wrapV: 1
40 | wrapW: 1
41 | nPOTScale: 1
42 | lightmap: 0
43 | compressionQuality: 50
44 | spriteMode: 0
45 | spriteExtrude: 1
46 | spriteMeshType: 1
47 | alignment: 0
48 | spritePivot: {x: 0.5, y: 0.5}
49 | spritePixelsToUnits: 100
50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0}
51 | spriteGenerateFallbackPhysicsShape: 1
52 | alphaUsage: 1
53 | alphaIsTransparency: 1
54 | spriteTessellationDetail: -1
55 | textureType: 0
56 | textureShape: 1
57 | singleChannelComponent: 0
58 | flipbookRows: 1
59 | flipbookColumns: 1
60 | maxTextureSizeSet: 0
61 | compressionQualitySet: 0
62 | textureFormatSet: 0
63 | ignorePngGamma: 0
64 | applyGammaDecoding: 0
65 | platformSettings:
66 | - serializedVersion: 3
67 | buildTarget: DefaultTexturePlatform
68 | maxTextureSize: 128
69 | resizeAlgorithm: 0
70 | textureFormat: -1
71 | textureCompression: 1
72 | compressionQuality: 50
73 | crunchedCompression: 0
74 | allowsAlphaSplitting: 0
75 | overridden: 0
76 | androidETC2FallbackOverride: 0
77 | forceMaximumCompressionQuality_BC6H_BC7: 0
78 | - serializedVersion: 3
79 | buildTarget: Standalone
80 | maxTextureSize: 128
81 | resizeAlgorithm: 0
82 | textureFormat: -1
83 | textureCompression: 1
84 | compressionQuality: 50
85 | crunchedCompression: 0
86 | allowsAlphaSplitting: 0
87 | overridden: 0
88 | androidETC2FallbackOverride: 0
89 | forceMaximumCompressionQuality_BC6H_BC7: 0
90 | - serializedVersion: 3
91 | buildTarget: WebGL
92 | maxTextureSize: 128
93 | resizeAlgorithm: 0
94 | textureFormat: -1
95 | textureCompression: 1
96 | compressionQuality: 50
97 | crunchedCompression: 0
98 | allowsAlphaSplitting: 0
99 | overridden: 0
100 | androidETC2FallbackOverride: 0
101 | forceMaximumCompressionQuality_BC6H_BC7: 0
102 | spriteSheet:
103 | serializedVersion: 2
104 | sprites: []
105 | outline: []
106 | physicsShape: []
107 | bones: []
108 | spriteID:
109 | internalID: 0
110 | vertices: []
111 | indices:
112 | edges: []
113 | weights: []
114 | secondaryTextures: []
115 | spritePackingTag:
116 | pSDRemoveMatte: 0
117 | pSDShowRemoveMatteOption: 0
118 | userData:
119 | assetBundleName:
120 | assetBundleVariant:
121 |
--------------------------------------------------------------------------------
/Resources/Connector_Line.png.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4add1f7d2539b204aa4d09272f3b4db9
3 | TextureImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 11
7 | mipmaps:
8 | mipMapMode: 0
9 | enableMipMap: 1
10 | sRGBTexture: 1
11 | linearTexture: 0
12 | fadeOut: 0
13 | borderMipMap: 0
14 | mipMapsPreserveCoverage: 0
15 | alphaTestReferenceValue: 0.5
16 | mipMapFadeDistanceStart: 1
17 | mipMapFadeDistanceEnd: 3
18 | bumpmap:
19 | convertToNormalMap: 0
20 | externalNormalMap: 0
21 | heightScale: 0.25
22 | normalMapFilter: 0
23 | isReadable: 0
24 | streamingMipmaps: 0
25 | streamingMipmapsPriority: 0
26 | vTOnly: 0
27 | grayScaleToAlpha: 0
28 | generateCubemap: 6
29 | cubemapConvolution: 0
30 | seamlessCubemap: 0
31 | textureFormat: 1
32 | maxTextureSize: 2048
33 | textureSettings:
34 | serializedVersion: 2
35 | filterMode: 0
36 | aniso: 1
37 | mipBias: 0
38 | wrapU: 1
39 | wrapV: 1
40 | wrapW: 1
41 | nPOTScale: 1
42 | lightmap: 0
43 | compressionQuality: 50
44 | spriteMode: 0
45 | spriteExtrude: 1
46 | spriteMeshType: 1
47 | alignment: 0
48 | spritePivot: {x: 0.5, y: 0.5}
49 | spritePixelsToUnits: 100
50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0}
51 | spriteGenerateFallbackPhysicsShape: 1
52 | alphaUsage: 1
53 | alphaIsTransparency: 1
54 | spriteTessellationDetail: -1
55 | textureType: 0
56 | textureShape: 1
57 | singleChannelComponent: 0
58 | flipbookRows: 1
59 | flipbookColumns: 1
60 | maxTextureSizeSet: 0
61 | compressionQualitySet: 0
62 | textureFormatSet: 0
63 | ignorePngGamma: 0
64 | applyGammaDecoding: 0
65 | platformSettings:
66 | - serializedVersion: 3
67 | buildTarget: DefaultTexturePlatform
68 | maxTextureSize: 128
69 | resizeAlgorithm: 0
70 | textureFormat: -1
71 | textureCompression: 1
72 | compressionQuality: 50
73 | crunchedCompression: 0
74 | allowsAlphaSplitting: 0
75 | overridden: 0
76 | androidETC2FallbackOverride: 0
77 | forceMaximumCompressionQuality_BC6H_BC7: 0
78 | - serializedVersion: 3
79 | buildTarget: Standalone
80 | maxTextureSize: 128
81 | resizeAlgorithm: 0
82 | textureFormat: -1
83 | textureCompression: 1
84 | compressionQuality: 50
85 | crunchedCompression: 0
86 | allowsAlphaSplitting: 0
87 | overridden: 0
88 | androidETC2FallbackOverride: 0
89 | forceMaximumCompressionQuality_BC6H_BC7: 0
90 | - serializedVersion: 3
91 | buildTarget: WebGL
92 | maxTextureSize: 128
93 | resizeAlgorithm: 0
94 | textureFormat: -1
95 | textureCompression: 1
96 | compressionQuality: 50
97 | crunchedCompression: 0
98 | allowsAlphaSplitting: 0
99 | overridden: 0
100 | androidETC2FallbackOverride: 0
101 | forceMaximumCompressionQuality_BC6H_BC7: 0
102 | spriteSheet:
103 | serializedVersion: 2
104 | sprites: []
105 | outline: []
106 | physicsShape: []
107 | bones: []
108 | spriteID:
109 | internalID: 0
110 | vertices: []
111 | indices:
112 | edges: []
113 | weights: []
114 | secondaryTextures: []
115 | spritePackingTag:
116 | pSDRemoveMatte: 0
117 | pSDShowRemoveMatteOption: 0
118 | userData:
119 | assetBundleName:
120 | assetBundleVariant:
121 |
--------------------------------------------------------------------------------
/Resources/Connector_End_Line.png.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4b451fb98c4e99e4cabcdf3e3276093c
3 | TextureImporter:
4 | internalIDToNameTable: []
5 | externalObjects: {}
6 | serializedVersion: 11
7 | mipmaps:
8 | mipMapMode: 0
9 | enableMipMap: 1
10 | sRGBTexture: 1
11 | linearTexture: 0
12 | fadeOut: 0
13 | borderMipMap: 0
14 | mipMapsPreserveCoverage: 0
15 | alphaTestReferenceValue: 0.5
16 | mipMapFadeDistanceStart: 1
17 | mipMapFadeDistanceEnd: 3
18 | bumpmap:
19 | convertToNormalMap: 0
20 | externalNormalMap: 0
21 | heightScale: 0.25
22 | normalMapFilter: 0
23 | isReadable: 0
24 | streamingMipmaps: 0
25 | streamingMipmapsPriority: 0
26 | vTOnly: 0
27 | grayScaleToAlpha: 0
28 | generateCubemap: 6
29 | cubemapConvolution: 0
30 | seamlessCubemap: 0
31 | textureFormat: 1
32 | maxTextureSize: 2048
33 | textureSettings:
34 | serializedVersion: 2
35 | filterMode: 0
36 | aniso: 1
37 | mipBias: 0
38 | wrapU: 1
39 | wrapV: 1
40 | wrapW: 1
41 | nPOTScale: 1
42 | lightmap: 0
43 | compressionQuality: 50
44 | spriteMode: 0
45 | spriteExtrude: 1
46 | spriteMeshType: 1
47 | alignment: 0
48 | spritePivot: {x: 0.5, y: 0.5}
49 | spritePixelsToUnits: 100
50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0}
51 | spriteGenerateFallbackPhysicsShape: 1
52 | alphaUsage: 1
53 | alphaIsTransparency: 1
54 | spriteTessellationDetail: -1
55 | textureType: 0
56 | textureShape: 1
57 | singleChannelComponent: 0
58 | flipbookRows: 1
59 | flipbookColumns: 1
60 | maxTextureSizeSet: 0
61 | compressionQualitySet: 0
62 | textureFormatSet: 0
63 | ignorePngGamma: 0
64 | applyGammaDecoding: 0
65 | platformSettings:
66 | - serializedVersion: 3
67 | buildTarget: DefaultTexturePlatform
68 | maxTextureSize: 128
69 | resizeAlgorithm: 0
70 | textureFormat: -1
71 | textureCompression: 1
72 | compressionQuality: 50
73 | crunchedCompression: 0
74 | allowsAlphaSplitting: 0
75 | overridden: 0
76 | androidETC2FallbackOverride: 0
77 | forceMaximumCompressionQuality_BC6H_BC7: 0
78 | - serializedVersion: 3
79 | buildTarget: Standalone
80 | maxTextureSize: 128
81 | resizeAlgorithm: 0
82 | textureFormat: -1
83 | textureCompression: 1
84 | compressionQuality: 50
85 | crunchedCompression: 0
86 | allowsAlphaSplitting: 0
87 | overridden: 0
88 | androidETC2FallbackOverride: 0
89 | forceMaximumCompressionQuality_BC6H_BC7: 0
90 | - serializedVersion: 3
91 | buildTarget: WebGL
92 | maxTextureSize: 128
93 | resizeAlgorithm: 0
94 | textureFormat: -1
95 | textureCompression: 1
96 | compressionQuality: 50
97 | crunchedCompression: 0
98 | allowsAlphaSplitting: 0
99 | overridden: 0
100 | androidETC2FallbackOverride: 0
101 | forceMaximumCompressionQuality_BC6H_BC7: 0
102 | spriteSheet:
103 | serializedVersion: 2
104 | sprites: []
105 | outline: []
106 | physicsShape: []
107 | bones: []
108 | spriteID:
109 | internalID: 0
110 | vertices: []
111 | indices:
112 | edges: []
113 | weights: []
114 | secondaryTextures: []
115 | spritePackingTag:
116 | pSDRemoveMatte: 0
117 | pSDShowRemoveMatteOption: 0
118 | userData:
119 | assetBundleName:
120 | assetBundleVariant:
121 |
--------------------------------------------------------------------------------
/Editor/PreferencesWindow.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using Nomnom.EasierCustomPreferences.Editor;
4 | using UnityEditor;
5 | using UnityEngine;
6 |
7 | namespace Nomnom.HierarchyWindowExtensions.Editor {
8 | [PreferencesName("Hierarchy Window Extensions", "Nomnom")]
9 | internal static class PreferencesWindow {
10 | public static bool UseCustomLines { get; private set; }
11 | public static bool UseCustomIcons { get; private set; }
12 |
13 | private const string DEF_PREFAB = "NOM_HIERARCHY_PREFAB";
14 |
15 | private const string KEY_USE_CUSTOM_LINES = "nomnom.hierarchy-window-extensions.use-lines";
16 | private const string KEY_USE_CUSTOM_ICONS = "nomnom.hierarchy-window-extensions.use-icons";
17 | private const string KEY_USE_CUSTOM_PREFAB = "nomnom.hierarchy-window-extensions.use-prefab";
18 |
19 | private static GUIContent _useCustomLinesText = new GUIContent("Use Custom Lines");
20 | private static GUIContent _useCustomIconsText = new GUIContent("Use Custom Icons");
21 | private static GUIContent _useMultiPrefabText = new GUIContent("Use Multi-Select Prefab Creation");
22 |
23 | [InitializeOnLoadMethod]
24 | private static void AssignFromPrefs() {
25 | UseCustomLines = EditorPrefs.GetBool(KEY_USE_CUSTOM_LINES, true);
26 | UseCustomIcons = EditorPrefs.GetBool(KEY_USE_CUSTOM_ICONS, true);
27 | }
28 |
29 | [SettingsProvider]
30 | public static SettingsProvider CreateProvider() => CustomPreferences.GetProvider(typeof(PreferencesWindow));
31 |
32 | public static Settings OnDeserialize() {
33 | AssignFromPrefs();
34 |
35 | return new Settings {
36 | UseLines = UseCustomLines,
37 | UseIcons = UseCustomIcons,
38 | UseMultiPrefab = EditorPrefs.GetBool(KEY_USE_CUSTOM_PREFAB, false),
39 | };
40 | }
41 |
42 | public static void OnSerialize(Settings settings) {
43 | EditorPrefs.SetBool(KEY_USE_CUSTOM_LINES, settings.UseLines);
44 | EditorPrefs.SetBool(KEY_USE_CUSTOM_ICONS, settings.UseIcons);
45 | EditorPrefs.SetBool(KEY_USE_CUSTOM_PREFAB, settings.UseMultiPrefab);
46 |
47 | if (settings.UseIcons != UseCustomIcons && !settings.UseIcons) {
48 | CoreHierarchyPass.ResetTree();
49 | }
50 |
51 | AssignFromPrefs();
52 | }
53 |
54 | public static void OnGUI(string searchContext, Settings obj) {
55 | GUI.enabled = !EditorApplication.isCompiling;
56 |
57 | if (!GUI.enabled) {
58 | EditorGUILayout.HelpBox("The Editor is currently recompiling...", MessageType.Info);
59 | }
60 |
61 | EditorGUI.indentLevel++;
62 | EditorGUILayout.HelpBox("Shows custom line connectors across scene objects.", MessageType.Info);
63 | obj.UseLines = EditorGUILayout.ToggleLeft(_useCustomLinesText, obj.UseLines);
64 | EditorGUILayout.HelpBox("Shows icons on scene objects that reflect object state.", MessageType.Info);
65 | obj.UseIcons = EditorGUILayout.ToggleLeft(_useCustomIconsText, obj.UseIcons);
66 |
67 | EditorGUI.BeginChangeCheck();
68 | EditorGUILayout.HelpBox("Shows a context option for creating multiple prefabs from a multi-selection in \"Prefab/Multi-Prefab\".", MessageType.Info);
69 | obj.UseMultiPrefab = EditorGUILayout.ToggleLeft(_useMultiPrefabText, obj.UseMultiPrefab);
70 |
71 | if (EditorGUI.EndChangeCheck()) {
72 | // update preprocessors
73 | string definesString =
74 | PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
75 | List allDefines = definesString.Split(';').ToList();
76 |
77 | bool containsMultiPrefab = allDefines.Contains(DEF_PREFAB);
78 |
79 | if (containsMultiPrefab && !obj.UseMultiPrefab) {
80 | allDefines.Remove(DEF_PREFAB);
81 | } else if (!containsMultiPrefab && obj.UseMultiPrefab) {
82 | allDefines.Add(DEF_PREFAB);
83 | }
84 |
85 | PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, string.Join(";", allDefines));
86 | AssetDatabase.Refresh();
87 |
88 | OnSerialize(obj);
89 | }
90 |
91 | EditorGUI.indentLevel--;
92 | }
93 |
94 | internal sealed class Settings {
95 | public bool UseLines;
96 | public bool UseIcons;
97 | public bool UseMultiPrefab;
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/Editor/ObjectConnector.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEditor;
3 | using UnityEditor.Callbacks;
4 | using UnityEngine;
5 | using UnityEngine.SceneManagement;
6 |
7 | namespace Nomnom.HierarchyWindowExtensions.Editor {
8 | ///
9 | /// Adds a custom line type between hierarchy objects
10 | ///
11 | internal static class ObjectConnector {
12 | private static Texture _dashedLineTexture;
13 | private static Texture _connectorLineTexture;
14 | private static Texture _connectorLineEndTexture;
15 | private static Material _textureMaterial;
16 | private static Dictionary _nodes;
17 | private static int _rootChildCount;
18 |
19 | [DidReloadScripts]
20 | private static void ReloadResources() {
21 | _dashedLineTexture = Resources.Load("Dashed_Line");
22 | _connectorLineTexture = Resources.Load("Connector_Line");
23 | _connectorLineEndTexture = Resources.Load("Connector_End_Line");
24 | _textureMaterial = Resources.Load("Dashed_Line_Mat");
25 |
26 | UpdateNodes();
27 | }
28 |
29 | [InitializeOnLoadMethod]
30 | private static void OnLoad() {
31 | _nodes = new Dictionary();
32 |
33 | EditorApplication.hierarchyChanged += OnHierarchyChanged;
34 |
35 | OnHierarchyChanged();
36 | ReloadResources();
37 | }
38 |
39 | private static void OnHierarchyChanged() {
40 | UpdateNodes();
41 |
42 | _rootChildCount = SceneManager.GetActiveScene().GetRootGameObjects().Length;
43 | }
44 |
45 | public static void Draw(int instanceId, in Rect rect) {
46 | // draw dashed line when in a parent, but not the root parent
47 | Object obj = EditorUtility.InstanceIDToObject(instanceId);
48 | if (!(obj is GameObject gameObject)) {
49 | return;
50 | }
51 |
52 | Rect localDashRect = rect;
53 | localDashRect.x -= 16;
54 | localDashRect.width = 16;
55 | localDashRect.height = 16;
56 |
57 | // draw persistent dashed line
58 | Rect initialDashedRect = localDashRect;
59 | initialDashedRect.x = 30;
60 |
61 | if (!_nodes.TryGetValue(gameObject, out HierarchyNode node)) {
62 | return;
63 | }
64 |
65 | Transform transform = node.Transform;
66 |
67 | for (int i = 0; i < node.ParentCount; i++) {
68 | DrawDashedLine(initialDashedRect);
69 |
70 | initialDashedRect.x += 14;
71 | }
72 |
73 | if (transform.childCount > 0) {
74 | return;
75 | }
76 |
77 | bool isEnd = transform.parent && node.Index == transform.parent.childCount - 1 ||
78 | !transform.parent && node.Index == _rootChildCount - 1;
79 | DrawConnectorLine(localDashRect, isEnd);
80 | }
81 |
82 | private static void DrawDashedLine(in Rect rect) {
83 | if (!_dashedLineTexture || !_textureMaterial) {
84 | ReloadResources();
85 | return;
86 | }
87 |
88 | EditorGUI.DrawPreviewTexture(rect, _dashedLineTexture, _textureMaterial);
89 | }
90 |
91 | private static void DrawConnectorLine(in Rect rect, bool isEnd) {
92 | if (!_connectorLineEndTexture || !_connectorLineTexture || !_textureMaterial) {
93 | ReloadResources();
94 | return;
95 | }
96 |
97 | EditorGUI.DrawPreviewTexture(rect, isEnd ? _connectorLineEndTexture : _connectorLineTexture, _textureMaterial);
98 | }
99 |
100 | private static void UpdateNodes() {
101 | // update tree
102 | _nodes.Clear();
103 |
104 | GameObject[] objects = Object.FindObjectsOfType();
105 | foreach (GameObject gameObject in objects) {
106 | Transform transform = gameObject.transform;
107 |
108 | _nodes.Add(gameObject, new HierarchyNode {
109 | Transform = transform,
110 | Index = transform.GetSiblingIndex(),
111 | ParentCount = countParents(transform),
112 | ChildCount = transform.childCount
113 | });
114 | }
115 |
116 | int countParents(Transform transform) {
117 | int count = 1;
118 |
119 | while (transform.parent) {
120 | transform = transform.parent;
121 | count++;
122 | }
123 |
124 | return count;
125 | }
126 | }
127 |
128 | private class HierarchyNode {
129 | public Transform Transform;
130 | public int Index;
131 | public int ParentCount;
132 | public int ChildCount;
133 | }
134 | }
135 | }
--------------------------------------------------------------------------------