├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CONTRIBUTING.md ├── CONTRIBUTING.md.meta ├── Editor.meta ├── Editor ├── FolderEditor.cs ├── FolderEditor.cs.meta ├── FolderEditorUtils.cs ├── FolderEditorUtils.cs.meta ├── Icon Handling.meta ├── Icon Handling │ ├── HierarchyFolderIcon.cs │ ├── HierarchyFolderIcon.cs.meta │ ├── ReplaceColor Shader.shader │ ├── ReplaceColor Shader.shader.meta │ ├── TextureHelper.cs │ └── TextureHelper.cs.meta ├── Prefab Handling.meta ├── Prefab Handling │ ├── AssetImportGrouper.cs │ ├── AssetImportGrouper.cs.meta │ ├── ChangedPrefabs.cs │ ├── ChangedPrefabs.cs.meta │ ├── LabelHandler.cs │ ├── LabelHandler.cs.meta │ ├── PrefabFolderStripper.cs │ └── PrefabFolderStripper.cs.meta ├── Settings.meta ├── Settings │ ├── SettingsDrawer.cs │ ├── SettingsDrawer.cs.meta │ ├── StripSettings.cs │ └── StripSettings.cs.meta ├── UnityHierarchyFolders.Editor.asmdef └── UnityHierarchyFolders.Editor.asmdef.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── Folder.cs ├── Folder.cs.meta ├── StrippingMode.cs ├── StrippingMode.cs.meta ├── UnityHierarchyFolders.Runtime.asmdef └── UnityHierarchyFolders.Runtime.asmdef.meta ├── Tests.meta ├── Tests ├── Example.unity └── Example.unity.meta ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Apply native OS line-endings on checkout of these files... 2 | *.boo text 3 | *.c text 4 | *.cginc text 5 | *.config text 6 | *.contentproj text 7 | *.cpp text 8 | *.dae text 9 | *.DAE text 10 | *.dtd text 11 | *.fx text 12 | *.glsl text 13 | *.h text 14 | *.inc text 15 | *.ini text 16 | *.js text 17 | *.JSFL text 18 | *.jsfl text 19 | *.json text 20 | *.log text 21 | *.md text 22 | *.mel text 23 | *.php text 24 | *.shader text 25 | *.txt text 26 | *.TXT text 27 | *.xaml text 28 | *.xml text 29 | *.xsd text 30 | .gitattributes text 31 | .gitignore text 32 | COPYING text 33 | INSTALL* text 34 | KEYS* text 35 | LICENSE* text 36 | NEWS* text 37 | NOTICE* text 38 | README* text 39 | TODO* text 40 | WHATSNEW* text 41 | 42 | # Apply Unix-style LF line-endings on checkout of these files... 43 | *.meta text eol=lf 44 | *.sh text eol=lf 45 | *.vspscc text eol=lf 46 | .htaccess text eol=lf 47 | 48 | # Previous "binary" 49 | *.unity text eol=lf 50 | # having asset as text eol=lf caused terrain data not to be saved correctly 51 | *.asset binary 52 | *.prefab text eol=lf 53 | 54 | # Apply Windows/DOS-style CR-LF line-endings on checkout of these files... 55 | *.bat text eol=crlf 56 | *.cmd text eol=crlf 57 | *.csproj text eol=crlf 58 | *.sln text eol=crlf 59 | *.user text eol=crlf 60 | *.vcproj text eol=crlf 61 | *.cs text eol=crlf 62 | *.css text eol=crlf 63 | *.htm text eol=crlf 64 | *.html text eol=crlf 65 | 66 | # No end-of-line conversions are applied (i.e., "-text -diff") to these files... 67 | *.7z binary 68 | *.ai binary 69 | *.anim binary 70 | *.apk binary 71 | *.bin binary 72 | *.bmp binary 73 | *.BMP binary 74 | *.com binary 75 | *.COM binary 76 | *.controller binary 77 | *.cubemap binary 78 | *.dex binary 79 | *.dll binary 80 | *.DLL binary 81 | *.dylib binary 82 | *.eps binary 83 | *.exe binary 84 | *.EXE binary 85 | *.exr binary 86 | *.fbx binary 87 | *.FBX binary 88 | *.fla binary 89 | *.flare binary 90 | *.flv binary 91 | *.gif binary 92 | *.guiskin binary 93 | *.gz binary 94 | *.ht binary 95 | *.ico binary 96 | *.jpeg binary 97 | *.jpg binary 98 | *.keystore binary 99 | *.mask binary 100 | *.mat binary 101 | *.mb binary 102 | *.mp3 binary 103 | *.mp4 binary 104 | *.mpg binary 105 | *.ogg binary 106 | *.PCX binary 107 | *.pcx binary 108 | *.pdb binary 109 | *.pdf binary 110 | *.physicMaterial binary 111 | *.physicmaterial binary 112 | *.png binary 113 | *.ps binary 114 | *.psd binary 115 | *.qt binary 116 | *.so binary 117 | *.swf binary 118 | *.tga binary 119 | *.tif binary 120 | *.tiff binary 121 | *.ttf binary 122 | *.TTF binary 123 | *.unitypackage binary 124 | *.unityPackage binary 125 | *.wav binary 126 | *.wmv binary 127 | *.zip binary 128 | *.ZIP binary 129 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Anything that goes wrong, or usability stuff we missed 4 | title: "(bug) " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description 11 | 12 | **What exactly is going wrong? Please be as precise as possible, but you don't have to be too detailed if the bug is easily reproducible.** 13 | 14 | ## Environment 15 | - **Unity version (e.g. 2019.3f11):** 16 | - **Any settings that you think may be applicable:** 17 | - **OS version if you know this is an OS specific issue. Include as much detail as you need (e.g. Windows 10 Home Edition, macOS 10.15 Catalina):** 18 | 19 | ## Steps to Reproduce 20 | - **Do you remember what activity you were in when the issue happened?** 21 | - **What steps did you take?** 22 | - **What happens when you take those steps?** 23 | - **Can you reproduce it consistently, or does it only happen sometimes? If it is inconsistent, do you recognize any patterns of when it occurs? (you don't have to be the expert though -- casual observations will suffice)** 24 | - **Are there any other known errors that aren't related to this one, but might look the same?** 25 | 26 | ## Expected Behavior 27 | **If it isn't immediately obvious, what do you expect to happen? Is it clearly an error, or does it work as intended, but behave in such a way that makes the component awkward or complicated to used?** 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "(feature)" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description 11 | 12 | **What exactly would you like to see? Be precise, but you don't have to work out the details here.** 13 | 14 | ## Use Cases 15 | 16 | **If it isn't super obvious why someone would want this feature, please explain where you would use it. If there is more than one use case, then please list them here.** 17 | 18 | **Would any of these changes conflict with other features? If so, how would you propose to resolve them?** 19 | 20 | ## Mockups 21 | 22 | **Do you have any visualizations, or flow charts? They would be appreciated, but not strictly required.** 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Visual Studio 2015 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 | 26 | # Unity3D generated meta files 27 | *.pidb.meta 28 | 29 | # Unity3D Generated File On Crash Reports 30 | sysinfo.txt 31 | 32 | # Builds 33 | *.apk 34 | *.unitypackage 35 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | I'll just keep it nice and short, since this is such a small project. 4 | 5 | - Keep brackets on the same line, use spaces instead of tabs, and be smart about comments and variable names. 6 | - Good commit messages (doesn't matter which style). 7 | - Be nice please. 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2bdf3a7b3f45f40a5bcf99cf3dda41b3 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8370f994d28094d389909b3ac0a84aef 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/FolderEditor.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_2019_1_OR_NEWER 2 | using UnityEditor; 3 | using UnityEngine; 4 | using UnityHierarchyFolders.Runtime; 5 | 6 | namespace UnityHierarchyFolders.Editor 7 | { 8 | [CustomEditor(typeof(Folder))] 9 | public class FolderEditor : UnityEditor.Editor 10 | { 11 | private bool _expanded = false; 12 | 13 | public override bool RequiresConstantRepaint() => true; 14 | public override void OnInspectorGUI() 15 | { 16 | this._expanded = EditorGUILayout.Foldout(this._expanded, "Icon Color", true); 17 | if (this._expanded) { this.RenderColorPicker(); } 18 | } 19 | 20 | private void RenderColorPicker() 21 | { 22 | var colorIndexProperty = this.serializedObject.FindProperty("_colorIndex"); 23 | 24 | EditorGUILayout.BeginHorizontal(); 25 | GUILayout.FlexibleSpace(); 26 | 27 | float buttonSize = 25f; 28 | 29 | var gridRect = EditorGUILayout.GetControlRect(false, buttonSize * HierarchyFolderIcon.IconRowCount, 30 | GUILayout.Width(buttonSize * HierarchyFolderIcon.IconColumnCount)); 31 | 32 | int currentIndex = colorIndexProperty.intValue; 33 | for (int row = 0; row < HierarchyFolderIcon.IconRowCount; row++) 34 | { 35 | for (int column = 0; column < HierarchyFolderIcon.IconColumnCount; column++) 36 | { 37 | int index = 1 + column + row * HierarchyFolderIcon.IconColumnCount; 38 | float width = gridRect.width / HierarchyFolderIcon.IconColumnCount; 39 | float height = gridRect.height / HierarchyFolderIcon.IconRowCount; 40 | var rect = new Rect(gridRect.x + width * column, gridRect.y + height * row, width, height); 41 | (var openIcon, var closeIcon) = HierarchyFolderIcon.ColoredFolderIcons(index); 42 | 43 | if (Event.current.type == EventType.Repaint) 44 | { 45 | if (index == currentIndex) 46 | { 47 | GUIStyle hover = "TV Selection"; 48 | hover.Draw(rect, false, false, false, false); 49 | } 50 | else if (rect.Contains(Event.current.mousePosition)) 51 | { 52 | GUI.backgroundColor = new Color(.7f, .7f, .7f, 1f); 53 | GUIStyle white = "WhiteBackground"; 54 | white.Draw(rect, false, false, true, false); 55 | GUI.backgroundColor = Color.white; 56 | } 57 | } 58 | 59 | if (GUI.Button(rect, currentIndex == index ? openIcon : closeIcon, EditorStyles.label)) 60 | { 61 | Undo.RecordObject(this.target, "Set Folder Color"); 62 | colorIndexProperty.intValue = currentIndex == index ? 0 : index; 63 | this.serializedObject.ApplyModifiedProperties(); 64 | EditorApplication.RepaintHierarchyWindow(); 65 | GUIUtility.ExitGUI(); 66 | } 67 | } 68 | } 69 | 70 | GUILayout.FlexibleSpace(); 71 | EditorGUILayout.EndHorizontal(); 72 | 73 | GUILayout.Space(10f); 74 | } 75 | } 76 | } 77 | #endif -------------------------------------------------------------------------------- /Editor/FolderEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c336a8f369270f74e895d8dbed4b3f5d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/FolderEditorUtils.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEditor.Build; 3 | using UnityEditor.Build.Reporting; 4 | using UnityEngine; 5 | using UnityEngine.SceneManagement; 6 | using UnityHierarchyFolders.Runtime; 7 | 8 | namespace UnityHierarchyFolders.Editor 9 | { 10 | public static class FolderEditorUtils 11 | { 12 | private const string _actionName = "Create Hierarchy Folder %#&N"; 13 | 14 | /// Add new folder "prefab". 15 | /// Menu command information. 16 | [MenuItem("GameObject/" + _actionName, isValidateFunction: false, priority: 0)] 17 | public static void AddFolderPrefab(MenuCommand command) 18 | { 19 | var obj = new GameObject { name = "Folder" }; 20 | obj.AddComponent(); 21 | 22 | GameObjectUtility.SetParentAndAlign(obj, (GameObject)command.context); 23 | Undo.RegisterCreatedObjectUndo(obj, _actionName); 24 | Selection.activeObject = obj; 25 | } 26 | } 27 | 28 | public class FolderOnBuild : IProcessSceneWithReport 29 | { 30 | public int callbackOrder => 0; 31 | 32 | public void OnProcessScene(Scene scene, BuildReport report) 33 | { 34 | var strippingMode = report == null ? StripSettings.PlayMode : StripSettings.Build; 35 | 36 | foreach (var folder in Object.FindObjectsOfType()) 37 | { 38 | folder.Flatten(strippingMode, StripSettings.CapitalizeName); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Editor/FolderEditorUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6810d6ae38b004696bfe74282dce3d48 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Icon Handling.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9b9b359874c54b8e9968bce99b84b1cd 3 | timeCreated: 1613920209 -------------------------------------------------------------------------------- /Editor/Icon Handling/HierarchyFolderIcon.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_2019_1_OR_NEWER 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using UnityEditor; 8 | using UnityEditor.IMGUI.Controls; 9 | using UnityEngine; 10 | using UnityHierarchyFolders.Runtime; 11 | using Object = UnityEngine.Object; 12 | 13 | namespace UnityHierarchyFolders.Editor 14 | { 15 | public static class HierarchyFolderIcon 16 | { 17 | #if UNITY_2020_1_OR_NEWER 18 | private const string _openedFolderPrefix = "FolderOpened"; 19 | #else 20 | private const string _openedFolderPrefix = "OpenedFolder"; 21 | #endif 22 | private const string _closedFolderPrefix = "Folder"; 23 | 24 | private static Texture2D _openFolderTexture; 25 | private static Texture2D _closedFolderTexture; 26 | private static Texture2D _openFolderSelectedTexture; 27 | private static Texture2D _closedFolderSelectedTexture; 28 | 29 | private static bool _isInitialized; 30 | private static bool _hasProcessedFrame = true; 31 | 32 | // Reflected members 33 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 34 | private static PropertyInfo prop_sceneHierarchy; 35 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 36 | private static PropertyInfo prop_treeView; 37 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 38 | private static PropertyInfo prop_data; 39 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 40 | private static PropertyInfo prop_selectedIcon; 41 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 42 | private static PropertyInfo prop_objectPPTR; 43 | 44 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 45 | private static MethodInfo meth_getRows; 46 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 47 | private static MethodInfo meth_isExpanded; 48 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Special naming scheme")] 49 | private static MethodInfo meth_getAllSceneHierarchyWindows; 50 | 51 | private static (Texture2D open, Texture2D closed)[] _coloredFolderIcons; 52 | public static (Texture2D open, Texture2D closed) ColoredFolderIcons(int i) => _coloredFolderIcons[i]; 53 | 54 | public static int IconColumnCount => IconColors.GetLength(0); 55 | public static int IconRowCount => IconColors.GetLength(1); 56 | 57 | private static readonly Color[,] IconColors = { 58 | {new Color(0.09f, 0.57f, 0.82f), new Color(0.05f, 0.34f, 0.48f),}, 59 | {new Color(0.09f, 0.67f, 0.67f), new Color(0.05f, 0.42f, 0.42f),}, 60 | {new Color(0.23f, 0.73f, 0.36f), new Color(0.15f, 0.41f, 0.22f),}, 61 | {new Color(0.55f, 0.35f, 0.71f), new Color(0.35f, 0.24f, 0.44f),}, 62 | {new Color(0.78f, 0.27f, 0.55f), new Color(0.52f, 0.15f, 0.35f),}, 63 | {new Color(0.80f, 0.66f, 0.10f), new Color(0.56f, 0.46f, 0.02f),}, 64 | {new Color(0.91f, 0.49f, 0.13f), new Color(0.62f, 0.33f, 0.07f),}, 65 | {new Color(0.91f, 0.30f, 0.24f), new Color(0.77f, 0.15f, 0.09f),}, 66 | {new Color(0.35f, 0.49f, 0.63f), new Color(0.24f, 0.33f, 0.42f),}, 67 | }; 68 | 69 | [InitializeOnLoadMethod] 70 | private static void Startup() 71 | { 72 | EditorApplication.update += ResetFolderIcons; 73 | EditorApplication.hierarchyWindowItemOnGUI += RefreshFolderIcons; 74 | } 75 | 76 | private static void InitIfNeeded() 77 | { 78 | if (_isInitialized) { return; } 79 | 80 | _openFolderTexture = (Texture2D)EditorGUIUtility.IconContent($"{_openedFolderPrefix} Icon").image; 81 | _closedFolderTexture = (Texture2D)EditorGUIUtility.IconContent($"{_closedFolderPrefix} Icon").image; 82 | 83 | // We could use the actual white folder icons but I prefer the look of the tinted white folder icon 84 | // To use the actual white version: 85 | // texture = (Texture2D) EditorGUIUtility.IconContent($"{OpenedFolderPrefix | ClosedFolderPrefix} On Icon").image; 86 | _openFolderSelectedTexture = TextureHelper.GetWhiteTexture(_openFolderTexture, $"{_openedFolderPrefix} Icon White"); 87 | _closedFolderSelectedTexture = TextureHelper.GetWhiteTexture(_closedFolderTexture, $"{_closedFolderPrefix} Icon White"); 88 | 89 | _coloredFolderIcons = new (Texture2D, Texture2D)[] { (_openFolderTexture, _closedFolderTexture) }; 90 | 91 | for (int row = 0; row < IconRowCount; row++) 92 | { 93 | for (int column = 0; column < IconColumnCount; column++) 94 | { 95 | int index = 1 + column + row * IconColumnCount; 96 | var color = IconColors[column, row]; 97 | 98 | var openFolderIcon = TextureHelper.GetTintedTexture(_openFolderSelectedTexture, 99 | color, $"{_openFolderSelectedTexture.name} {index}"); 100 | var closedFolderIcon = TextureHelper.GetTintedTexture(_closedFolderSelectedTexture, 101 | color, $"{_closedFolderSelectedTexture.name} {index}"); 102 | 103 | ArrayUtility.Add(ref _coloredFolderIcons, (openFolderIcon, closedFolderIcon)); 104 | } 105 | } 106 | 107 | // reflection 108 | 109 | const BindingFlags BindingAll = BindingFlags.Public 110 | | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance; 111 | 112 | var assembly = typeof(SceneView).Assembly; 113 | 114 | var type_sceneHierarchyWindow = assembly.GetType("UnityEditor.SceneHierarchyWindow"); 115 | meth_getAllSceneHierarchyWindows = type_sceneHierarchyWindow.GetMethod("GetAllSceneHierarchyWindows", BindingAll); 116 | prop_sceneHierarchy = type_sceneHierarchyWindow.GetProperty("sceneHierarchy"); 117 | 118 | var type_sceneHierarchy = assembly.GetType("UnityEditor.SceneHierarchy"); 119 | prop_treeView = type_sceneHierarchy.GetProperty("treeView", BindingAll); 120 | 121 | var type_treeViewController = assembly.GetType("UnityEditor.IMGUI.Controls.TreeViewController"); 122 | prop_data = type_treeViewController.GetProperty("data", BindingAll); 123 | 124 | var type_iTreeViewDataSource = assembly.GetType("UnityEditor.IMGUI.Controls.ITreeViewDataSource"); 125 | meth_getRows = type_iTreeViewDataSource.GetMethod("GetRows"); 126 | meth_isExpanded = type_iTreeViewDataSource.GetMethod("IsExpanded", new Type[] { typeof(TreeViewItem) }); 127 | 128 | var type_gameObjectTreeViewItem = assembly.GetType("UnityEditor.GameObjectTreeViewItem"); 129 | prop_selectedIcon = type_gameObjectTreeViewItem.GetProperty("selectedIcon", BindingAll); 130 | prop_objectPPTR = type_gameObjectTreeViewItem.GetProperty("objectPPTR", BindingAll); 131 | 132 | _isInitialized = true; 133 | } 134 | 135 | private static void ResetFolderIcons() 136 | { 137 | InitIfNeeded(); 138 | _hasProcessedFrame = false; 139 | } 140 | 141 | private static void RefreshFolderIcons(int instanceid, Rect selectionrect) 142 | { 143 | if (_hasProcessedFrame) { return; } 144 | 145 | _hasProcessedFrame = true; 146 | 147 | var windows = ((IEnumerable)meth_getAllSceneHierarchyWindows.Invoke(null, Array.Empty())).Cast().ToList(); 148 | foreach (var window in windows) 149 | { 150 | object sceneHierarchy = prop_sceneHierarchy.GetValue(window); 151 | object treeView = prop_treeView.GetValue(sceneHierarchy); 152 | object data = prop_data.GetValue(treeView); 153 | 154 | var rows = (IList)meth_getRows.Invoke(data, Array.Empty()); 155 | foreach (var item in rows) 156 | { 157 | var itemObject = (Object)prop_objectPPTR.GetValue(item); 158 | if (!Folder.TryGetIconIndex(itemObject, out int colorIndex)) { continue; } 159 | 160 | bool isExpanded = (bool)meth_isExpanded.Invoke(data, new object[] { item }); 161 | 162 | var icons = ColoredFolderIcons(Mathf.Clamp(colorIndex, 0, _coloredFolderIcons.Length - 1)); 163 | 164 | item.icon = isExpanded ? icons.open : icons.closed; 165 | 166 | prop_selectedIcon.SetValue(item, isExpanded ? _openFolderSelectedTexture : _closedFolderSelectedTexture); 167 | } 168 | } 169 | } 170 | } 171 | } 172 | #endif -------------------------------------------------------------------------------- /Editor/Icon Handling/HierarchyFolderIcon.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6f29c3d38f5ea94dbfbf44facaeaaca 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Icon Handling/ReplaceColor Shader.shader: -------------------------------------------------------------------------------- 1 | Shader "UI/Replace color" { 2 | 3 | Properties 4 | { 5 | _Color ("Replace Color", Color) = (1,1,1) 6 | _MainTex ("Texture", 2D) = "white" 7 | } 8 | 9 | SubShader 10 | { 11 | Pass 12 | { 13 | SetTexture [_MainTex] 14 | { 15 | ConstantColor [_Color] 16 | combine constant + texture, texture 17 | } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Editor/Icon Handling/ReplaceColor Shader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7b9019de4b525b349a48678a64d7983a 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Editor/Icon Handling/TextureHelper.cs: -------------------------------------------------------------------------------- 1 | // This software includes third-party software subject to the associated copyrights, as follows: 2 | // 3 | // Name: SolidUtilities 4 | // Repo: https://github.com/SolidAlloy/SolidUtilities 5 | // License: MIT (https://github.com/SolidAlloy/SolidUtilities/blob/master/LICENSE) 6 | // Copyright (c) 2020 SolidAlloy 7 | 8 | namespace UnityHierarchyFolders.Editor 9 | { 10 | using System; 11 | using JetBrains.Annotations; 12 | using UnityEngine; 13 | 14 | /// Helps to create new textures. 15 | internal static class TextureHelper 16 | { 17 | private static readonly Color _fullyTransparent = new Color(1f, 1f, 1f, 0f); 18 | 19 | private static Material _tintMaterial; 20 | private static Material _colorReplaceMaterial; 21 | 22 | public static Texture2D GetTintedTexture(Texture2D original, Color tint, string name) 23 | { 24 | return GetTextureWithMaterial(original, GetTintMaterial(tint), name); 25 | } 26 | 27 | public static Texture2D GetWhiteTexture(Texture2D original, string name) 28 | { 29 | return GetTextureWithMaterial(original, GetColorReplaceMaterial(Color.white), name); 30 | } 31 | 32 | private static Material GetTintMaterial(Color tint) 33 | { 34 | if (_tintMaterial == null) 35 | _tintMaterial = new Material(Shader.Find("UI/Default")); 36 | 37 | _tintMaterial.color = tint; 38 | return _tintMaterial; 39 | } 40 | 41 | private static Material GetColorReplaceMaterial(Color color) 42 | { 43 | if (_colorReplaceMaterial == null) 44 | _colorReplaceMaterial = new Material(Shader.Find("UI/Replace color")); 45 | 46 | _colorReplaceMaterial.color = color; 47 | return _colorReplaceMaterial; 48 | } 49 | 50 | private static Texture2D GetTextureWithMaterial(Texture2D original, Material material, string name) 51 | { 52 | Texture2D newTexture; 53 | 54 | using (new SRGBWriteScope(true)) 55 | { 56 | using (var temporary = new TemporaryActiveTexture(original.width, original.height, 0)) 57 | { 58 | GL.Clear(false, true, _fullyTransparent); 59 | 60 | Graphics.Blit(original, temporary, material); 61 | 62 | newTexture = new Texture2D(original.width, original.width, TextureFormat.ARGB32, false, true) 63 | { 64 | name = name, 65 | filterMode = FilterMode.Bilinear, 66 | hideFlags = HideFlags.DontSave 67 | }; 68 | 69 | newTexture.ReadPixels(new Rect(0f, 0f, original.width, original.width), 0, 0); 70 | newTexture.alphaIsTransparency = true; 71 | newTexture.Apply(); 72 | } 73 | } 74 | 75 | return newTexture; 76 | } 77 | 78 | /// 79 | /// Temporarily sets to the passed value, then returns it back. 80 | /// 81 | [PublicAPI] 82 | public readonly struct SRGBWriteScope : IDisposable 83 | { 84 | private readonly bool _previousValue; 85 | 86 | /// Temporarily sets to true, then executes the action. 87 | /// Temporary value of . 88 | /// 89 | /// using (new SRGBWriteScope(true)) 90 | /// { 91 | /// GL.Clear(false, true, new Color(1f, 1f, 1f, 0f)); 92 | /// Graphics.Blit(Default, temporary, material); 93 | /// }); 94 | /// 95 | public SRGBWriteScope(bool enableWrite) 96 | { 97 | _previousValue = GL.sRGBWrite; 98 | GL.sRGBWrite = enableWrite; 99 | } 100 | 101 | public void Dispose() 102 | { 103 | GL.sRGBWrite = _previousValue; 104 | } 105 | } 106 | 107 | /// 108 | /// Creates a temporary texture, sets it as active in , then removes the changes 109 | /// and sets the previous active texture back automatically. 110 | /// 111 | /// 112 | /// 113 | /// using (var temporaryActiveTexture = new TemporaryActiveTexture(icon.width, icon.height, 0)) 114 | /// { 115 | /// Graphics.Blit(icon, temporary, material); 116 | /// }); 117 | /// 118 | [PublicAPI] 119 | public class TemporaryActiveTexture : IDisposable 120 | { 121 | private readonly RenderTexture _previousActiveTexture; 122 | private readonly TemporaryRenderTexture _value; 123 | 124 | /// 125 | /// Creates a temporary texture, sets it as active in , then removes it 126 | /// and sets the previous active texture back automatically. 127 | /// 128 | /// Width of the temporary texture in pixels. 129 | /// Height of the temporary texture in pixels. 130 | /// Depth buffer of the temporary texture. 131 | /// 132 | /// 133 | /// using (var temporaryActiveTexture = new TemporaryActiveTexture(icon.width, icon.height, 0)) 134 | /// { 135 | /// Graphics.Blit(icon, temporary, material); 136 | /// }); 137 | /// 138 | public TemporaryActiveTexture(int width, int height, int depthBuffer) 139 | { 140 | _previousActiveTexture = RenderTexture.active; 141 | _value = new TemporaryRenderTexture(width, height, depthBuffer); 142 | RenderTexture.active = _value; 143 | } 144 | 145 | public static implicit operator RenderTexture(TemporaryActiveTexture temporaryTexture) => temporaryTexture._value; 146 | 147 | public void Dispose() 148 | { 149 | _value.Dispose(); 150 | RenderTexture.active = _previousActiveTexture; 151 | } 152 | } 153 | 154 | /// Creates a temporary texture that can be used and then removed automatically. 155 | /// 156 | /// 157 | /// using (var temporaryTexture = new TemporaryRenderTexture(icon.width, icon.height, 0)) 158 | /// { 159 | /// Graphics.Blit(icon, temporaryTexture, material); 160 | /// }); 161 | /// 162 | [PublicAPI] 163 | public class TemporaryRenderTexture : IDisposable 164 | { 165 | private readonly RenderTexture _value; 166 | 167 | /// Creates a temporary texture that can be used and then removed automatically. 168 | /// Width of the temporary texture in pixels. 169 | /// Height of the temporary texture in pixels. 170 | /// Depth buffer of the temporary texture. 171 | /// 172 | /// 173 | /// using (var temporaryTexture = new TemporaryRenderTexture(icon.width, icon.height, 0)) 174 | /// { 175 | /// Graphics.Blit(icon, temporaryTexture, material); 176 | /// }); 177 | /// 178 | public TemporaryRenderTexture(int width, int height, int depthBuffer) 179 | { 180 | _value = RenderTexture.GetTemporary(width, height, depthBuffer); 181 | } 182 | 183 | public static implicit operator RenderTexture(TemporaryRenderTexture temporaryRenderTexture) => temporaryRenderTexture._value; 184 | 185 | public void Dispose() 186 | { 187 | RenderTexture.ReleaseTemporary(_value); 188 | } 189 | } 190 | } 191 | } -------------------------------------------------------------------------------- /Editor/Icon Handling/TextureHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d329b59d6a342b995af79657ee830da 3 | timeCreated: 1613913214 -------------------------------------------------------------------------------- /Editor/Prefab Handling.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 622698139ac84600a4ba37348572c363 3 | timeCreated: 1613932303 -------------------------------------------------------------------------------- /Editor/Prefab Handling/AssetImportGrouper.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Editor 2 | { 3 | using System; 4 | using UnityEditor; 5 | 6 | internal class AssetImportGrouper : IDisposable 7 | { 8 | private static AssetImportGrouper _instance; 9 | 10 | private AssetImportGrouper() { } 11 | 12 | public static AssetImportGrouper Init() 13 | { 14 | AssetDatabase.StartAssetEditing(); 15 | 16 | if (_instance == null) 17 | _instance = new AssetImportGrouper(); 18 | 19 | return _instance; 20 | } 21 | 22 | public void Dispose() 23 | { 24 | AssetDatabase.StopAssetEditing(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Editor/Prefab Handling/AssetImportGrouper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f8101e4361cb4d5db8f6b03b4add2359 3 | timeCreated: 1614092011 -------------------------------------------------------------------------------- /Editor/Prefab Handling/ChangedPrefabs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Editor 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using UnityEditor; 7 | using UnityEngine; 8 | 9 | /// 10 | /// A singleton that contains info about edited prefabs and persists changes between domain reloads. 11 | /// 12 | [Serializable] 13 | internal class ChangedPrefabs : IEnumerable> 14 | { 15 | private const string KeyName = nameof(ChangedPrefabs); 16 | 17 | [SerializeField] private string[] _guids; 18 | [SerializeField] private string[] _contents; 19 | 20 | private static ChangedPrefabs _instance; 21 | 22 | public static ChangedPrefabs Instance 23 | { 24 | get 25 | { 26 | // _instance is null only in PrefabFolderStripper.RevertChanges() when Instance is called for the first time. 27 | // If _instance is null at that point, it means the domain reloaded, so the instance must be retrieved from PlayerPrefs. 28 | // In all other cases, _instance is created with help of Initialize before operating on it, so FromDeserialized won't be called. 29 | if (_instance == null) 30 | { 31 | _instance = FromDeserialized(); 32 | } 33 | 34 | return _instance; 35 | } 36 | } 37 | 38 | public (string guid, string content) this[int index] 39 | { 40 | get => (_guids[index], _contents[index]); 41 | set 42 | { 43 | _guids[index] = value.guid; 44 | _contents[index] = value.content; 45 | } 46 | } 47 | 48 | public static void Initialize(int length) 49 | { 50 | _instance = new ChangedPrefabs 51 | { 52 | _guids = new string[length], 53 | _contents = new string[length] 54 | }; 55 | } 56 | 57 | public static void SerializeIfNeeded() 58 | { 59 | // Serialization is only needed if prefabs are edited before entering play mode and the domain will reload. 60 | // In all other cases, changes to prefabs will be reverted before a domain reload. 61 | #if UNITY_2019_3_OR_NEWER 62 | if (EditorSettings.enterPlayModeOptionsEnabled && EditorSettings.enterPlayModeOptions.HasFlag(EnterPlayModeOptions.DisableDomainReload)) 63 | return; 64 | #endif 65 | 66 | string serializedObject = EditorJsonUtility.ToJson(Instance); 67 | PlayerPrefs.SetString(KeyName, serializedObject); 68 | } 69 | 70 | private static ChangedPrefabs FromDeserialized() 71 | { 72 | string serializedObject = PlayerPrefs.GetString(KeyName); 73 | PlayerPrefs.DeleteKey(KeyName); 74 | var instance = new ChangedPrefabs(); 75 | EditorJsonUtility.FromJsonOverwrite(serializedObject, instance); 76 | return instance; 77 | } 78 | 79 | public Enumerator GetEnumerator() => new Enumerator(this); 80 | 81 | IEnumerator<(string, string)> IEnumerable>.GetEnumerator() 82 | { 83 | return GetEnumerator(); 84 | } 85 | 86 | IEnumerator IEnumerable.GetEnumerator() 87 | { 88 | return GetEnumerator(); 89 | } 90 | 91 | public struct Enumerator : IEnumerator> 92 | { 93 | private readonly ChangedPrefabs _instance; 94 | private int _index; 95 | 96 | public Enumerator(ChangedPrefabs instance) 97 | { 98 | _instance = instance; 99 | _index = -1; 100 | } 101 | 102 | public bool MoveNext() 103 | { 104 | return ++_index < Instance._guids.Length; 105 | } 106 | 107 | public void Reset() => _index = 0; 108 | 109 | public (string, string) Current => _instance[_index]; 110 | 111 | object IEnumerator.Current => Current; 112 | 113 | public void Dispose() { } 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /Editor/Prefab Handling/ChangedPrefabs.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 730dba92b19e4b9f81f4fb7583b55b0d 3 | timeCreated: 1614076027 -------------------------------------------------------------------------------- /Editor/Prefab Handling/LabelHandler.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Editor 2 | { 3 | using System.Linq; 4 | using Runtime; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | public class LabelHandler : AssetPostprocessor 9 | { 10 | public const string FolderPrefabLabel = "FolderUser"; 11 | 12 | private static void OnPostprocessAllAssets(string[] importedAssets, string[] _, string[] __, string[] ___) 13 | { 14 | // Group imports into one to improve performance in case there are multiple prefabs that need a label change. 15 | using (AssetImportGrouper.Init()) 16 | { 17 | foreach (string assetPath in importedAssets) 18 | { 19 | if (assetPath.EndsWith(".prefab")) 20 | HandlePrefabLabels(assetPath); 21 | } 22 | } 23 | } 24 | 25 | private static void HandlePrefabLabels(string assetPath) 26 | { 27 | var asset = AssetDatabase.LoadAssetAtPath(assetPath); 28 | 29 | if (asset.GetComponentsInChildren().Length == 0) 30 | { 31 | RemoveFolderLabel(asset, assetPath); 32 | } 33 | else 34 | { 35 | AddFolderLabel(asset, assetPath); 36 | } 37 | } 38 | 39 | private static void RemoveFolderLabel(GameObject assetObject, string assetPath) 40 | { 41 | var labels = AssetDatabase.GetLabels(assetObject); 42 | 43 | if ( ! labels.Contains(FolderPrefabLabel)) 44 | return; 45 | 46 | ArrayUtility.Remove(ref labels, FolderPrefabLabel); 47 | AssetDatabase.SetLabels(assetObject, labels); 48 | AssetDatabase.ImportAsset(assetPath); 49 | } 50 | 51 | private static void AddFolderLabel(GameObject assetObject, string assetPath) 52 | { 53 | var labels = AssetDatabase.GetLabels(assetObject); 54 | 55 | if (labels.Contains(FolderPrefabLabel)) 56 | return; 57 | 58 | ArrayUtility.Add(ref labels, FolderPrefabLabel); 59 | AssetDatabase.SetLabels(assetObject, labels); 60 | AssetDatabase.ImportAsset(assetPath); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Editor/Prefab Handling/LabelHandler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87092d606cab43079d7ad3ed41b9ab08 3 | timeCreated: 1613932316 -------------------------------------------------------------------------------- /Editor/Prefab Handling/PrefabFolderStripper.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Editor 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using Runtime; 7 | using UnityEditor; 8 | using UnityEditor.Build; 9 | using UnityEditor.Build.Reporting; 10 | using UnityEditor.Callbacks; 11 | using UnityEngine; 12 | using Object = UnityEngine.Object; 13 | 14 | [InitializeOnLoad] 15 | public class PrefabFolderStripper : IPreprocessBuildWithReport, IPostprocessBuildWithReport 16 | { 17 | static PrefabFolderStripper() 18 | { 19 | EditorApplication.playModeStateChanged += HandlePrefabsOnPlayMode; 20 | } 21 | 22 | public int callbackOrder => 0; 23 | 24 | public void OnPreprocessBuild(BuildReport report) 25 | { 26 | if (StripSettings.StripFoldersFromPrefabsInBuild) 27 | { 28 | using (AssetImportGrouper.Init()) 29 | { 30 | StripFoldersFromDependentPrefabs(); 31 | } 32 | } 33 | } 34 | 35 | public void OnPostprocessBuild(BuildReport report) 36 | { 37 | if (StripSettings.StripFoldersFromPrefabsInBuild) 38 | RevertChanges(); 39 | } 40 | 41 | private static void HandlePrefabsOnPlayMode(PlayModeStateChange state) 42 | { 43 | if ( ! StripSettings.StripFoldersFromPrefabsInPlayMode || StripSettings.PlayMode == StrippingMode.DoNothing) 44 | return; 45 | 46 | // Calling it not in EnteredPlayMode because scripts may instantiate prefabs in Awake or OnEnable 47 | // which happens before EnteredPlayMode. 48 | if (state == PlayModeStateChange.ExitingEditMode) 49 | { 50 | // Stripping folders from all prefabs in the project instead of only the ones referenced in the scenes 51 | // because a prefab may be hot-swapped in Play Mode. 52 | using (AssetImportGrouper.Init()) 53 | { 54 | StripFoldersFromAllPrefabs(); 55 | } 56 | } 57 | else if (state == PlayModeStateChange.ExitingPlayMode) 58 | { 59 | RevertChanges(); 60 | } 61 | } 62 | 63 | private static void StripFoldersFromDependentPrefabs() 64 | { 65 | var scenePaths = EditorBuildSettings.scenes.Select(scene => scene.path).ToArray(); 66 | var dependentAssetsPaths = AssetDatabase.GetDependencies(scenePaths, true); 67 | 68 | var prefabsWithLabel = dependentAssetsPaths.Where(path => 69 | AssetDatabase.GetLabels(GetAssetForLabel(path)).Contains(LabelHandler.FolderPrefabLabel)) 70 | .ToArray(); 71 | 72 | ChangedPrefabs.Initialize(prefabsWithLabel.Length); 73 | 74 | for (int i = 0; i < prefabsWithLabel.Length; i++) 75 | { 76 | string path = prefabsWithLabel[i]; 77 | ChangedPrefabs.Instance[i] = (AssetDatabase.AssetPathToGUID(path), File.ReadAllText(path)); 78 | StripFoldersFromPrefab(path, StripSettings.Build); 79 | } 80 | 81 | // Serialization of ChangedPrefabs is not needed here because domain doesn't reload before changes are reverted. 82 | } 83 | 84 | private static 85 | #if UNITY_2020_1_OR_NEWER 86 | GUID 87 | #else 88 | UnityEngine.Object 89 | #endif 90 | GetAssetForLabel(string path) 91 | { 92 | #if UNITY_2020_1_OR_NEWER 93 | return AssetDatabase.GUIDFromAssetPath(path); 94 | #else 95 | return AssetDatabase.LoadAssetAtPath(path); 96 | #endif 97 | } 98 | 99 | private static void StripFoldersFromAllPrefabs() 100 | { 101 | var prefabGUIDs = AssetDatabase.FindAssets($"l: {LabelHandler.FolderPrefabLabel}"); 102 | ChangedPrefabs.Initialize(prefabGUIDs.Length); 103 | 104 | for (int i = 0; i < prefabGUIDs.Length; i++) 105 | { 106 | string guid = prefabGUIDs[i]; 107 | string path = AssetDatabase.GUIDToAssetPath(guid); 108 | 109 | ChangedPrefabs.Instance[i] = (guid, File.ReadAllText(path)); 110 | StripFoldersFromPrefab(path, StripSettings.PlayMode); 111 | } 112 | 113 | // If domain reload is enabled in Play Mode Options, serialization of the changed prefabs is necessary 114 | // so that changes can be reverted after leaving play mode. 115 | ChangedPrefabs.SerializeIfNeeded(); 116 | } 117 | 118 | private static void StripFoldersFromPrefab(string prefabPath, StrippingMode strippingMode) 119 | { 120 | using (var temp = new EditPrefabContentsScope(prefabPath)) 121 | { 122 | var folders = temp.PrefabContentsRoot.GetComponentsInChildren(); 123 | 124 | foreach (Folder folder in folders) 125 | { 126 | if (folder.gameObject == temp.PrefabContentsRoot) 127 | { 128 | Debug.LogWarning( 129 | $"Hierarchy will not flatten for {prefabPath} because its root is a folder. " + 130 | "It's advised to make the root an empty game object."); 131 | 132 | Object.DestroyImmediate(folder); 133 | } 134 | else 135 | { 136 | folder.Flatten(strippingMode, StripSettings.CapitalizeName); 137 | } 138 | } 139 | } 140 | } 141 | 142 | private static void RevertChanges() 143 | { 144 | foreach ((string guid, string content) in ChangedPrefabs.Instance) 145 | { 146 | string path = AssetDatabase.GUIDToAssetPath(guid); 147 | 148 | // The asset might have been deleted in Play Mode. Additionally, event if the asset is deleted, 149 | // AssetDatabase might still hold a reference to it, so a File.Exists check is needed. 150 | if (string.IsNullOrEmpty(path) || ! File.Exists(path)) 151 | continue; 152 | 153 | File.WriteAllText(path, content); 154 | } 155 | 156 | AssetDatabase.Refresh(); 157 | } 158 | 159 | /// 160 | /// A copy of for backwards compatibility with Unity 2019. 161 | /// 162 | private readonly struct EditPrefabContentsScope : IDisposable 163 | { 164 | public readonly GameObject PrefabContentsRoot; 165 | 166 | private readonly string _assetPath; 167 | 168 | public EditPrefabContentsScope(string assetPath) 169 | { 170 | PrefabContentsRoot = PrefabUtility.LoadPrefabContents(assetPath); 171 | _assetPath = assetPath; 172 | } 173 | 174 | public void Dispose() 175 | { 176 | PrefabUtility.SaveAsPrefabAsset(PrefabContentsRoot, _assetPath); 177 | PrefabUtility.UnloadPrefabContents(PrefabContentsRoot); 178 | } 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /Editor/Prefab Handling/PrefabFolderStripper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9ef711838a3d4ac7ae9b012d5a52f29e 3 | timeCreated: 1613934498 -------------------------------------------------------------------------------- /Editor/Settings.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ad62f65af064679bce3c5950b3afaed 3 | timeCreated: 1614010587 -------------------------------------------------------------------------------- /Editor/Settings/SettingsDrawer.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Editor 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using Runtime; 6 | using UnityEditor; 7 | using UnityEngine; 8 | 9 | internal static class SettingsDrawer 10 | { 11 | /// 12 | /// Field names of corresponding settings. Each field name can be accessed by the name of the setting variable. 13 | /// 14 | private static readonly Dictionary _fieldNames = new Dictionary 15 | { 16 | { nameof(StripSettings.PlayMode), "Play Mode Stripping Type" }, 17 | { nameof(StripSettings.Build), "Build Stripping Type" }, 18 | { nameof(StripSettings.CapitalizeName), "Capitalize Folder Names" }, 19 | { nameof(StripSettings.StripFoldersFromPrefabsInPlayMode), "Strip folders from prefabs in Play Mode" }, 20 | { nameof(StripSettings.StripFoldersFromPrefabsInBuild), "Strip folders from prefabs in build" }, 21 | }; 22 | 23 | private static readonly GUIContent _buildStrippingName = new GUIContent(_fieldNames[nameof(StripSettings.Build)]); 24 | 25 | [SettingsProvider] 26 | public static SettingsProvider CreateSettingsProvider() 27 | { 28 | return new SettingsProvider("Preferences/Hierarchy Folders", SettingsScope.User) 29 | { 30 | guiHandler = OnGUI, 31 | keywords = GetKeywords() 32 | }; 33 | } 34 | 35 | private static void OnGUI(string searchContext) 36 | { 37 | StripSettings.PlayMode = (StrippingMode) EditorGUILayout.EnumPopup( 38 | _fieldNames[nameof(StripSettings.PlayMode)], StripSettings.PlayMode); 39 | 40 | if (StripSettings.PlayMode == StrippingMode.ReplaceWithSeparator) 41 | { 42 | StripSettings.CapitalizeName = EditorGUILayout.Toggle( 43 | _fieldNames[nameof(StripSettings.CapitalizeName)], StripSettings.CapitalizeName); 44 | } 45 | 46 | StripSettings.Build = (StrippingMode) EditorGUILayout.EnumPopup( 47 | _buildStrippingName, StripSettings.Build, TypeCanBeInBuild, true); 48 | 49 | EditorGUILayout.Space(EditorGUIUtility.singleLineHeight); 50 | 51 | if (StripSettings.StripFoldersFromPrefabsInPlayMode) 52 | { 53 | EditorGUILayout.HelpBox( 54 | "If you notice that entering play mode takes too long, you can try disabling this option. " + 55 | "Folders will not be stripped from prefabs that are instantiated at runtime, but if performance in " + 56 | "Play Mode does not matter, you will be fine.", MessageType.Info); 57 | } 58 | 59 | using (new TemporaryLabelWidth(230f)) 60 | { 61 | StripSettings.StripFoldersFromPrefabsInPlayMode = 62 | EditorGUILayout.Toggle(_fieldNames[nameof(StripSettings.StripFoldersFromPrefabsInPlayMode)], StripSettings.StripFoldersFromPrefabsInPlayMode); 63 | 64 | StripSettings.StripFoldersFromPrefabsInBuild = 65 | EditorGUILayout.Toggle(_fieldNames[nameof(StripSettings.StripFoldersFromPrefabsInBuild)], StripSettings.StripFoldersFromPrefabsInBuild); 66 | } 67 | } 68 | 69 | private static HashSet GetKeywords() 70 | { 71 | var keywords = new HashSet(); 72 | 73 | foreach (string fieldName in _fieldNames.Values) 74 | { 75 | keywords.AddWords(fieldName); 76 | } 77 | 78 | return keywords; 79 | } 80 | 81 | private static void AddWords(this HashSet set, string phrase) 82 | { 83 | foreach (string word in phrase.Split(' ')) 84 | { 85 | set.Add(word); 86 | } 87 | } 88 | 89 | private static bool TypeCanBeInBuild(Enum enumValue) 90 | { 91 | var mode = (StrippingMode) enumValue; 92 | return mode == StrippingMode.PrependWithFolderName || mode == StrippingMode.Delete; 93 | } 94 | 95 | /// 96 | /// Temporarily sets to a certain value, than reverts it. 97 | /// 98 | private readonly struct TemporaryLabelWidth : IDisposable 99 | { 100 | private readonly float _oldWidth; 101 | 102 | public TemporaryLabelWidth(float width) 103 | { 104 | _oldWidth = EditorGUIUtility.labelWidth; 105 | EditorGUIUtility.labelWidth = width; 106 | } 107 | 108 | public void Dispose() 109 | { 110 | EditorGUIUtility.labelWidth = _oldWidth; 111 | } 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /Editor/Settings/SettingsDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 023a1385294f41a6a7d8ae3844629a7c 3 | timeCreated: 1613836312 -------------------------------------------------------------------------------- /Editor/Settings/StripSettings.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Editor 2 | { 3 | using Runtime; 4 | using UnityEditor; 5 | using UnityEditor.SettingsManagement; 6 | 7 | internal static class StripSettings 8 | { 9 | private const string PackageName = "com.xsduan.hierarchy-folders"; 10 | 11 | private static Settings _instance; 12 | private static UserSetting _playModeSetting; 13 | private static UserSetting _buildSetting; 14 | private static UserSetting _capitalizeName; 15 | private static UserSetting _stripFoldersFromPrefabsInPlayMode; 16 | private static UserSetting _stripFoldersFromPrefabsInBuild; 17 | 18 | public static StrippingMode PlayMode 19 | { 20 | get 21 | { 22 | InitializeIfNeeded(); 23 | return _playModeSetting.value; 24 | } 25 | 26 | set => _playModeSetting.value = value; 27 | } 28 | 29 | public static StrippingMode Build 30 | { 31 | get 32 | { 33 | InitializeIfNeeded(); 34 | return _buildSetting.value; 35 | } 36 | 37 | set => _buildSetting.value = value; 38 | } 39 | 40 | public static bool CapitalizeName 41 | { 42 | get 43 | { 44 | InitializeIfNeeded(); 45 | return _capitalizeName.value; 46 | } 47 | 48 | set => _capitalizeName.value = value; 49 | } 50 | 51 | public static bool StripFoldersFromPrefabsInPlayMode 52 | { 53 | get 54 | { 55 | InitializeIfNeeded(); 56 | return _stripFoldersFromPrefabsInPlayMode.value; 57 | } 58 | 59 | set => _stripFoldersFromPrefabsInPlayMode.value = value; 60 | } 61 | 62 | public static bool StripFoldersFromPrefabsInBuild 63 | { 64 | get 65 | { 66 | InitializeIfNeeded(); 67 | return _stripFoldersFromPrefabsInBuild.value; 68 | } 69 | 70 | set => _stripFoldersFromPrefabsInBuild.value = value; 71 | } 72 | 73 | private static void InitializeIfNeeded() 74 | { 75 | if (_instance != null) 76 | return; 77 | 78 | _instance = new Settings(PackageName); 79 | 80 | _playModeSetting = new UserSetting(_instance, nameof(_playModeSetting), 81 | StrippingMode.PrependWithFolderName, SettingsScope.Project); 82 | 83 | _buildSetting = new UserSetting(_instance, nameof(_buildSetting), 84 | StrippingMode.PrependWithFolderName, SettingsScope.Project); 85 | 86 | _capitalizeName = new UserSetting(_instance, nameof(_capitalizeName), true, SettingsScope.Project); 87 | 88 | _stripFoldersFromPrefabsInPlayMode = new UserSetting(_instance, 89 | nameof(_stripFoldersFromPrefabsInPlayMode), true, SettingsScope.Project); 90 | 91 | _stripFoldersFromPrefabsInBuild = new UserSetting(_instance, 92 | nameof(_stripFoldersFromPrefabsInBuild), true, SettingsScope.Project); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Editor/Settings/StripSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56180820a6f84c2b8654c24c9dddb507 3 | timeCreated: 1613843945 -------------------------------------------------------------------------------- /Editor/UnityHierarchyFolders.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UnityHierarchyFolders.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "UnityHierarchyFolders.Runtime", 6 | "Unity.Settings.Editor" 7 | ], 8 | "includePlatforms": [ 9 | "Editor" 10 | ], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /Editor/UnityHierarchyFolders.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 703c201eb02b87c4f828db366bed013e 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Shane Duan 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.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c72c84b9f5bec4223b4fbbdedccb5d60 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Folders for Unity Hierarchy 2 | 3 | Specialized folder objects for Unity Hierarchy. 4 | 5 | ## Installation 6 | 7 | This uses the new UPM system. The old copy-into-Assets method still works 8 | perfectly decent so if you don't want to bother with UPM just copy the `Editor` 9 | and `Runtime` folders into your project. 10 | 11 | To add this project, add a [git dependency][1] in your `manifest.json`: 12 | 13 | ```json 14 | { 15 | "dependencies": { 16 | "com.unity.package-manager-ui": "1.9.11", 17 | "com.xsduan.hierarchy-folders": "https://github.com/xsduan/unity-hierarchy-folders.git" 18 | } 19 | } 20 | ``` 21 | 22 | Older versions of Unity may have to use the relative link, ie: 23 | 24 | ```json 25 | { 26 | "dependencies": { 27 | "com.unity.package-manager-ui": "1.9.11", 28 | "com.xsduan.hierarchy-folders": "file:../../unity-hierarchy-folders" 29 | } 30 | } 31 | ``` 32 | 33 | A "Create Folder" menu item should show up in the GameObject menu. Add 34 | `Tests/Example.unity` to your current scene for an example of what hierarchy 35 | folders can do for you. 36 | 37 | The UPM does not have much documentation at the moment so it probably will be 38 | buggy, you're not going crazy! 39 | 40 | [1]: https://forum.unity.com/threads/git-support-on-package-manager.573673/#post-3819487 41 | 42 | ### OpenUPM 43 | 44 | Please note that this is a third party service, which means that Unity 45 | Technologies will not provide support. Always be mindful when considering 46 | unofficial plugins and tools. 47 | 48 | ``` 49 | $ openupm add com.xsduan.hierarchy-folders 50 | ``` 51 | 52 | To install OpenUPM, please see the [documentation][2]. 53 | 54 | [2]: https://openupm.com/docs/ 55 | 56 | ## Stripping Modes 57 | 58 | You can choose how exactly the folder will be removed from the hierarchy in **Preferences -> Hierarchy Folders**. 59 | 60 | The following stripping modes are available: 61 | 62 | - **Prepend With Folder Name** - The folder will be removed, and all child objects will be prepended with the folder name (e.g. childObject => Folder/childObject). This is the default behaviour. 63 | - **Delete** - The folder will be removed, and names of child objects will not change. 64 | - **Do Nothing** *(available only for Play Mode)* - The folder will not be removed, the hierarchy will not change in play mode. Use this mode if you don't need extra performance in Editor. 65 | - **Replace With Separator** *(available only for Play Mode)* - The hierarchy will flatten, and the folder will be replaced with a separator (e.g. "--- FOLDER ---"). Useful if you need extra performance in Editor but still want to see what folder game objects belong to. 66 | 67 | ## Stripping folders from prefabs 68 | 69 | With this plugin, it is possible to strip folders from prefabs that are not present in the scene but are instantiated at runtime. Upon entering Play Mode, the plugin goes through all prefabs containing folders and strips them. On exiting Play Mode, the changes are reverted. It shouldn't add significant overhead unless you have thousands of prefabs with folders inside, but if entering Play Mode takes too long, you can try disabling this option in **Preferences -> Hierarchy Folders**. You can also choose whether to strip folders from prefabs before they are packed into a build. 70 | 71 | ## Possible FAQs 72 | 73 | ### Why folders in the first place? 74 | 75 | As projects get bigger, they tend to get cluttered in the scene. It's very 76 | helpful if you can group them together into logical groups. 77 | 78 | #### Why delete them on build then? 79 | 80 | Because they are best used for level designers to declutter the hierarchy, but 81 | calculating the global transform from the local during runtime can take a 82 | noticeable impact on performance once scenes get to 1000, 10000, or more 83 | objects. 84 | 85 | #### So why can't I just use empty GameObjects and delete them on build? 86 | 87 | Sometimes empty GameObjects are used for other things and it's useful to have a 88 | specific type of object that should always be deleted on build. 89 | 90 | Besides, I did all the legwork, so you wouldn't have to! 91 | 92 | ### There's another product/widget that exists that does this exact task. 93 | 94 | So there are. This isn't exactly a unique concept and I only made it for future 95 | personal use and shared it only to possibly to help other people because I 96 | couldn't find it on Google. 97 | 98 | If you are the owner of one such product, please contact me and we can work 99 | something out. 100 | 101 | The hope is to have it be a native component like it is in Unreal. (Not 102 | necessarily this one specifically, but I'm not opposed to it ;) I've seen paid 103 | components for this and frankly for the effort it took me it's a bit of a 104 | rip-off to pay any amount for it. [Vote for this feature on the Unity 105 | Productboard if you agree!](https://portal.productboard.com/ca1chnbwvzw1eg5yjc5rijnj/c/392-hierarchy-folders) 106 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 75ad2a17b4a8147f49225e6d262f8df1 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c72b993b123c4daeb9b5c8324c42edc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Folder.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using UnityEditor; 6 | #endif 7 | using UnityEngine; 8 | 9 | namespace UnityHierarchyFolders.Runtime 10 | { 11 | #if UNITY_EDITOR 12 | /// 13 | /// Extension to Components to check if there are no dependencies to itself. 14 | /// 15 | /// taken from: 16 | /// 17 | /// StackOverflow: Check if a game object's component can be destroyed 18 | /// 19 | /// 20 | /// 21 | internal static class CanDestroyExtension 22 | { 23 | private static bool Requires(Type obj, Type req) => Attribute.IsDefined(obj, typeof(RequireComponent)) && 24 | Attribute.GetCustomAttributes(obj, typeof(RequireComponent)) 25 | .OfType() 26 | // RequireComponent has up to 3 required types per requireComponent, because of course. 27 | .SelectMany(rc => new Type[] { rc.m_Type0, rc.m_Type1, rc.m_Type2 }) 28 | .Any(t => t != null && t.IsAssignableFrom(req)); 29 | 30 | /// Checks whether the stated component can be destroyed without violating dependencies. 31 | /// Is component destroyable? 32 | /// Component candidate for destruction. 33 | internal static bool CanDestroy(this Component t) => !t.gameObject.GetComponents() 34 | .Any(c => Requires(c.GetType(), t.GetType())); 35 | } 36 | #endif 37 | 38 | [DisallowMultipleComponent] 39 | [ExecuteAlways] 40 | public class Folder : MonoBehaviour 41 | { 42 | #if UNITY_EDITOR 43 | private static bool _addedSelectionResetCallback; 44 | 45 | private Folder() 46 | { 47 | // add reset callback first in queue 48 | if (!_addedSelectionResetCallback) 49 | { 50 | Selection.selectionChanged += () => Tools.hidden = false; 51 | _addedSelectionResetCallback = true; 52 | } 53 | 54 | Selection.selectionChanged += this.HandleSelection; 55 | } 56 | 57 | private static Tool _lastTool; 58 | private static Folder _toolLock; 59 | 60 | [SerializeField] 61 | private int _colorIndex = 0; 62 | public int ColorIndex => this._colorIndex; 63 | 64 | /// 65 | /// The set of folder objects. 66 | /// 67 | public static Dictionary folders = new Dictionary(); 68 | 69 | /// 70 | /// Gets the icon index associated with the specified object. 71 | /// 72 | /// Test object. 73 | /// The icon index. 74 | /// True if the specified object is a folder with a registered icon index. 75 | public static bool TryGetIconIndex(UnityEngine.Object obj, out int index) 76 | { 77 | index = -1; 78 | return obj && folders.TryGetValue(obj.GetInstanceID(), out index); 79 | } 80 | 81 | /// 82 | /// Test if a Unity object is a folder by way of containing a Folder component. 83 | /// 84 | /// Test object. 85 | /// Is this object a folder? 86 | public static bool IsFolder(UnityEngine.Object obj) => folders.ContainsKey(obj.GetInstanceID()); 87 | 88 | private void Start() => this.AddFolderData(); 89 | private void OnValidate() => this.AddFolderData(); 90 | private void OnDestroy() => this.RemoveFolderData(); 91 | 92 | private void AddFolderData() => folders[this.gameObject.GetInstanceID()] = this._colorIndex; 93 | private void RemoveFolderData() => folders.Remove(this.gameObject.GetInstanceID()); 94 | 95 | /// Hides all gizmos if selected to avoid accidental editing of the transform. 96 | private void HandleSelection() 97 | { 98 | // ignore if another folder object is already hiding gizmo 99 | if (_toolLock != null && _toolLock != this) { return; } 100 | 101 | if (this != null && Selection.Contains(this.gameObject)) 102 | { 103 | _lastTool = Tools.current; 104 | _toolLock = this; 105 | Tools.current = Tool.None; 106 | } 107 | else if (_toolLock != null) 108 | { 109 | Tools.current = _lastTool; 110 | _toolLock = null; 111 | } 112 | } 113 | 114 | private bool AskDelete() => EditorUtility.DisplayDialog( 115 | title: "Can't add script", 116 | message: "Folders shouldn't be used with other components. Which component should be kept?", 117 | ok: "Folder", 118 | cancel: "Component" 119 | ); 120 | 121 | /// Delete all components regardless of dependency hierarchy. 122 | /// Which components to delete. 123 | private void DeleteComponents(IEnumerable comps) 124 | { 125 | var destroyable = comps.Where(c => c != null && c.CanDestroy()); 126 | 127 | // keep cycling through the list of components until all components are gone. 128 | while (destroyable.Any()) 129 | { 130 | foreach (var c in destroyable) 131 | { 132 | DestroyImmediate(c); 133 | } 134 | } 135 | } 136 | 137 | /// Ensure that the folder is the only component. 138 | private void EnsureExclusiveComponent() 139 | { 140 | // we are running, don't bother the player. 141 | // also, sometimes `this` might be null for whatever reason. 142 | if (Application.isPlaying || this == null) { return; } 143 | 144 | var existingComponents = this.GetComponents() 145 | .Where(c => c != this && !typeof(Transform).IsAssignableFrom(c.GetType())); 146 | 147 | // no items means no actions anyways 148 | if (!existingComponents.Any()) { return; } 149 | 150 | if (this.AskDelete()) 151 | { 152 | this.DeleteComponents(existingComponents); 153 | } 154 | else 155 | { 156 | DestroyImmediate(this); 157 | } 158 | } 159 | 160 | /// 161 | /// Hide inspector to prevent accidental editing of transform. 162 | /// 163 | private void OnEnable() => this.transform.hideFlags = HideFlags.HideInInspector; 164 | #endif 165 | 166 | /// 167 | /// Resets the transform properties to their identities, i.e. (0, 0, 0), (0˚, 0˚, 0˚), and (100%, 100%, 100%). 168 | /// 169 | private void Update() 170 | { 171 | this.transform.localPosition = Vector3.zero; 172 | this.transform.localRotation = Quaternion.identity; 173 | this.transform.localScale = Vector3.one; 174 | 175 | #if UNITY_EDITOR 176 | if (!Application.IsPlaying(this.gameObject)) 177 | { 178 | this.AddFolderData(); 179 | } 180 | 181 | this.EnsureExclusiveComponent(); 182 | #endif 183 | } 184 | 185 | /// Takes direct children and links them to the parent transform or global. 186 | /// Stripping mode to apply. 187 | /// 188 | /// Whether to capitalize the folder name when replacing it with a separator. 189 | /// Applies only if is 190 | /// 191 | public void Flatten(StrippingMode strippingMode, bool capitalizeFolderName) 192 | { 193 | if (strippingMode == StrippingMode.DoNothing) 194 | return; 195 | 196 | MoveChildrenOut(strippingMode); 197 | 198 | HandleSelf(strippingMode, capitalizeFolderName); 199 | } 200 | 201 | private void MoveChildrenOut(StrippingMode strippingMode) 202 | { 203 | int index = this.transform.GetSiblingIndex(); // keep components in logical order 204 | 205 | foreach (var child in GetComponentsInChildren(includeInactive: true)) 206 | { 207 | // gather only first-level children 208 | if (child.parent != this.transform) 209 | continue; 210 | 211 | if (strippingMode == StrippingMode.PrependWithFolderName) 212 | { 213 | child.name = $"{this.name}/{child.name}"; 214 | } 215 | 216 | child.SetParent(this.transform.parent, true); 217 | child.SetSiblingIndex(++index); 218 | } 219 | } 220 | 221 | private void HandleSelf(StrippingMode strippingMode, bool capitalizeFolderName) 222 | { 223 | if (strippingMode == StrippingMode.ReplaceWithSeparator) 224 | { 225 | // If the folder name is already a separator, don't change it. 226 | if ( ! name.StartsWith("--- ")) 227 | { 228 | name = $"--- {(capitalizeFolderName ? name.ToUpper() : name)} ---"; 229 | } 230 | 231 | return; 232 | } 233 | 234 | if (Application.isPlaying) 235 | { 236 | Destroy(this.gameObject); 237 | } 238 | else 239 | { 240 | DestroyImmediate(this.gameObject); 241 | } 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /Runtime/Folder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 149818d5acbed4455af27721dc46461a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {fileID: -1463847995985908582, guid: 0000000000000000d000000000000000, type: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/StrippingMode.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHierarchyFolders.Runtime 2 | { 3 | public enum StrippingMode 4 | { 5 | PrependWithFolderName, Delete, DoNothing, ReplaceWithSeparator 6 | } 7 | } -------------------------------------------------------------------------------- /Runtime/StrippingMode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3634a380eb0d4432a5396f7cdc085414 3 | timeCreated: 1613841896 -------------------------------------------------------------------------------- /Runtime/UnityHierarchyFolders.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UnityHierarchyFolders.Runtime", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } -------------------------------------------------------------------------------- /Runtime/UnityHierarchyFolders.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07bca6c7b5c28884cad3ed6593a01131 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7308dc3140fda4b3095f2282871f7bfa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Example.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 0 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 1 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 0 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 500 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 2 83 | m_PVRDenoiserTypeDirect: 0 84 | m_PVRDenoiserTypeIndirect: 0 85 | m_PVRDenoiserTypeAO: 0 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 0 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_UseShadowmask: 1 102 | --- !u!196 &4 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | debug: 122 | m_Flags: 0 123 | m_NavMeshData: {fileID: 0} 124 | --- !u!1 &15529379 125 | GameObject: 126 | m_ObjectHideFlags: 0 127 | m_CorrespondingSourceObject: {fileID: 0} 128 | m_PrefabInstance: {fileID: 0} 129 | m_PrefabAsset: {fileID: 0} 130 | serializedVersion: 6 131 | m_Component: 132 | - component: {fileID: 15529380} 133 | m_Layer: 0 134 | m_Name: a 135 | m_TagString: Untagged 136 | m_Icon: {fileID: 0} 137 | m_NavMeshLayer: 0 138 | m_StaticEditorFlags: 0 139 | m_IsActive: 1 140 | --- !u!4 &15529380 141 | Transform: 142 | m_ObjectHideFlags: 0 143 | m_CorrespondingSourceObject: {fileID: 0} 144 | m_PrefabInstance: {fileID: 0} 145 | m_PrefabAsset: {fileID: 0} 146 | m_GameObject: {fileID: 15529379} 147 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 148 | m_LocalPosition: {x: 0, y: 0, z: 0} 149 | m_LocalScale: {x: 1, y: 1, z: 1} 150 | m_Children: [] 151 | m_Father: {fileID: 463356207} 152 | m_RootOrder: 0 153 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 154 | --- !u!1 &132138651 155 | GameObject: 156 | m_ObjectHideFlags: 0 157 | m_CorrespondingSourceObject: {fileID: 0} 158 | m_PrefabInstance: {fileID: 0} 159 | m_PrefabAsset: {fileID: 0} 160 | serializedVersion: 6 161 | m_Component: 162 | - component: {fileID: 132138652} 163 | m_Layer: 0 164 | m_Name: f 165 | m_TagString: Untagged 166 | m_Icon: {fileID: 0} 167 | m_NavMeshLayer: 0 168 | m_StaticEditorFlags: 0 169 | m_IsActive: 1 170 | --- !u!4 &132138652 171 | Transform: 172 | m_ObjectHideFlags: 0 173 | m_CorrespondingSourceObject: {fileID: 0} 174 | m_PrefabInstance: {fileID: 0} 175 | m_PrefabAsset: {fileID: 0} 176 | m_GameObject: {fileID: 132138651} 177 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 178 | m_LocalPosition: {x: 0, y: 0, z: 0} 179 | m_LocalScale: {x: 1, y: 1, z: 1} 180 | m_Children: [] 181 | m_Father: {fileID: 1694949953} 182 | m_RootOrder: 1 183 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 184 | --- !u!1 &237864226 185 | GameObject: 186 | m_ObjectHideFlags: 0 187 | m_CorrespondingSourceObject: {fileID: 0} 188 | m_PrefabInstance: {fileID: 0} 189 | m_PrefabAsset: {fileID: 0} 190 | serializedVersion: 6 191 | m_Component: 192 | - component: {fileID: 237864227} 193 | - component: {fileID: 237864228} 194 | m_Layer: 0 195 | m_Name: Folder (1) 196 | m_TagString: EditorOnly 197 | m_Icon: {fileID: 0} 198 | m_NavMeshLayer: 0 199 | m_StaticEditorFlags: 0 200 | m_IsActive: 1 201 | --- !u!4 &237864227 202 | Transform: 203 | m_ObjectHideFlags: 2 204 | m_CorrespondingSourceObject: {fileID: 0} 205 | m_PrefabInstance: {fileID: 0} 206 | m_PrefabAsset: {fileID: 0} 207 | m_GameObject: {fileID: 237864226} 208 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 209 | m_LocalPosition: {x: 0, y: 0, z: 0} 210 | m_LocalScale: {x: 1, y: 1, z: 1} 211 | m_Children: [] 212 | m_Father: {fileID: 1831796945} 213 | m_RootOrder: 2 214 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 215 | --- !u!114 &237864228 216 | MonoBehaviour: 217 | m_ObjectHideFlags: 0 218 | m_CorrespondingSourceObject: {fileID: 0} 219 | m_PrefabInstance: {fileID: 0} 220 | m_PrefabAsset: {fileID: 0} 221 | m_GameObject: {fileID: 237864226} 222 | m_Enabled: 1 223 | m_EditorHideFlags: 0 224 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 225 | m_Name: 226 | m_EditorClassIdentifier: 227 | _colorIndex: 0 228 | --- !u!1 &290315314 229 | GameObject: 230 | m_ObjectHideFlags: 0 231 | m_CorrespondingSourceObject: {fileID: 0} 232 | m_PrefabInstance: {fileID: 0} 233 | m_PrefabAsset: {fileID: 0} 234 | serializedVersion: 6 235 | m_Component: 236 | - component: {fileID: 290315315} 237 | - component: {fileID: 290315316} 238 | m_Layer: 0 239 | m_Name: Folder 240 | m_TagString: EditorOnly 241 | m_Icon: {fileID: 0} 242 | m_NavMeshLayer: 0 243 | m_StaticEditorFlags: 0 244 | m_IsActive: 1 245 | --- !u!4 &290315315 246 | Transform: 247 | m_ObjectHideFlags: 2 248 | m_CorrespondingSourceObject: {fileID: 0} 249 | m_PrefabInstance: {fileID: 0} 250 | m_PrefabAsset: {fileID: 0} 251 | m_GameObject: {fileID: 290315314} 252 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 253 | m_LocalPosition: {x: 0, y: 0, z: 0} 254 | m_LocalScale: {x: 1, y: 1, z: 1} 255 | m_Children: [] 256 | m_Father: {fileID: 895580447} 257 | m_RootOrder: 2 258 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 259 | --- !u!114 &290315316 260 | MonoBehaviour: 261 | m_ObjectHideFlags: 0 262 | m_CorrespondingSourceObject: {fileID: 0} 263 | m_PrefabInstance: {fileID: 0} 264 | m_PrefabAsset: {fileID: 0} 265 | m_GameObject: {fileID: 290315314} 266 | m_Enabled: 1 267 | m_EditorHideFlags: 0 268 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 269 | m_Name: 270 | m_EditorClassIdentifier: 271 | _colorIndex: 0 272 | --- !u!1 &450170593 273 | GameObject: 274 | m_ObjectHideFlags: 0 275 | m_CorrespondingSourceObject: {fileID: 0} 276 | m_PrefabInstance: {fileID: 0} 277 | m_PrefabAsset: {fileID: 0} 278 | serializedVersion: 6 279 | m_Component: 280 | - component: {fileID: 450170594} 281 | m_Layer: 0 282 | m_Name: h 283 | m_TagString: Untagged 284 | m_Icon: {fileID: 0} 285 | m_NavMeshLayer: 0 286 | m_StaticEditorFlags: 0 287 | m_IsActive: 1 288 | --- !u!4 &450170594 289 | Transform: 290 | m_ObjectHideFlags: 0 291 | m_CorrespondingSourceObject: {fileID: 0} 292 | m_PrefabInstance: {fileID: 0} 293 | m_PrefabAsset: {fileID: 0} 294 | m_GameObject: {fileID: 450170593} 295 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 296 | m_LocalPosition: {x: 0, y: 0, z: 0} 297 | m_LocalScale: {x: 1, y: 1, z: 1} 298 | m_Children: [] 299 | m_Father: {fileID: 1694949953} 300 | m_RootOrder: 3 301 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 302 | --- !u!1 &463356205 303 | GameObject: 304 | m_ObjectHideFlags: 0 305 | m_CorrespondingSourceObject: {fileID: 0} 306 | m_PrefabInstance: {fileID: 0} 307 | m_PrefabAsset: {fileID: 0} 308 | serializedVersion: 6 309 | m_Component: 310 | - component: {fileID: 463356207} 311 | - component: {fileID: 463356206} 312 | m_Layer: 0 313 | m_Name: directly full folder 314 | m_TagString: EditorOnly 315 | m_Icon: {fileID: 0} 316 | m_NavMeshLayer: 0 317 | m_StaticEditorFlags: 0 318 | m_IsActive: 1 319 | --- !u!114 &463356206 320 | MonoBehaviour: 321 | m_ObjectHideFlags: 0 322 | m_CorrespondingSourceObject: {fileID: 0} 323 | m_PrefabInstance: {fileID: 0} 324 | m_PrefabAsset: {fileID: 0} 325 | m_GameObject: {fileID: 463356205} 326 | m_Enabled: 1 327 | m_EditorHideFlags: 0 328 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 329 | m_Name: 330 | m_EditorClassIdentifier: 331 | _colorIndex: 2 332 | --- !u!4 &463356207 333 | Transform: 334 | m_ObjectHideFlags: 2 335 | m_CorrespondingSourceObject: {fileID: 0} 336 | m_PrefabInstance: {fileID: 0} 337 | m_PrefabAsset: {fileID: 0} 338 | m_GameObject: {fileID: 463356205} 339 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 340 | m_LocalPosition: {x: 0, y: 0, z: 0} 341 | m_LocalScale: {x: 1, y: 1, z: 1} 342 | m_Children: 343 | - {fileID: 15529380} 344 | m_Father: {fileID: 0} 345 | m_RootOrder: 2 346 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 347 | --- !u!1 &526939265 348 | GameObject: 349 | m_ObjectHideFlags: 0 350 | m_CorrespondingSourceObject: {fileID: 0} 351 | m_PrefabInstance: {fileID: 0} 352 | m_PrefabAsset: {fileID: 0} 353 | serializedVersion: 6 354 | m_Component: 355 | - component: {fileID: 526939266} 356 | - component: {fileID: 526939267} 357 | m_Layer: 0 358 | m_Name: Folder 359 | m_TagString: EditorOnly 360 | m_Icon: {fileID: 0} 361 | m_NavMeshLayer: 0 362 | m_StaticEditorFlags: 0 363 | m_IsActive: 1 364 | --- !u!4 &526939266 365 | Transform: 366 | m_ObjectHideFlags: 2 367 | m_CorrespondingSourceObject: {fileID: 0} 368 | m_PrefabInstance: {fileID: 0} 369 | m_PrefabAsset: {fileID: 0} 370 | m_GameObject: {fileID: 526939265} 371 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 372 | m_LocalPosition: {x: 0, y: 0, z: 0} 373 | m_LocalScale: {x: 1, y: 1, z: 1} 374 | m_Children: 375 | - {fileID: 2052390214} 376 | m_Father: {fileID: 1131533464} 377 | m_RootOrder: 0 378 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 379 | --- !u!114 &526939267 380 | MonoBehaviour: 381 | m_ObjectHideFlags: 0 382 | m_CorrespondingSourceObject: {fileID: 0} 383 | m_PrefabInstance: {fileID: 0} 384 | m_PrefabAsset: {fileID: 0} 385 | m_GameObject: {fileID: 526939265} 386 | m_Enabled: 1 387 | m_EditorHideFlags: 0 388 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 389 | m_Name: 390 | m_EditorClassIdentifier: 391 | _colorIndex: 0 392 | --- !u!1 &607056353 393 | GameObject: 394 | m_ObjectHideFlags: 0 395 | m_CorrespondingSourceObject: {fileID: 0} 396 | m_PrefabInstance: {fileID: 0} 397 | m_PrefabAsset: {fileID: 0} 398 | serializedVersion: 6 399 | m_Component: 400 | - component: {fileID: 607056355} 401 | - component: {fileID: 607056354} 402 | m_Layer: 0 403 | m_Name: isolated recursive folder 404 | m_TagString: EditorOnly 405 | m_Icon: {fileID: 0} 406 | m_NavMeshLayer: 0 407 | m_StaticEditorFlags: 0 408 | m_IsActive: 1 409 | --- !u!114 &607056354 410 | MonoBehaviour: 411 | m_ObjectHideFlags: 0 412 | m_CorrespondingSourceObject: {fileID: 0} 413 | m_PrefabInstance: {fileID: 0} 414 | m_PrefabAsset: {fileID: 0} 415 | m_GameObject: {fileID: 607056353} 416 | m_Enabled: 1 417 | m_EditorHideFlags: 0 418 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 419 | m_Name: 420 | m_EditorClassIdentifier: 421 | _colorIndex: 1 422 | --- !u!4 &607056355 423 | Transform: 424 | m_ObjectHideFlags: 2 425 | m_CorrespondingSourceObject: {fileID: 0} 426 | m_PrefabInstance: {fileID: 0} 427 | m_PrefabAsset: {fileID: 0} 428 | m_GameObject: {fileID: 607056353} 429 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 430 | m_LocalPosition: {x: 0, y: 0, z: 0} 431 | m_LocalScale: {x: 1, y: 1, z: 1} 432 | m_Children: 433 | - {fileID: 1773556887} 434 | m_Father: {fileID: 0} 435 | m_RootOrder: 1 436 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 437 | --- !u!1 &726788904 438 | GameObject: 439 | m_ObjectHideFlags: 0 440 | m_CorrespondingSourceObject: {fileID: 0} 441 | m_PrefabInstance: {fileID: 0} 442 | m_PrefabAsset: {fileID: 0} 443 | serializedVersion: 6 444 | m_Component: 445 | - component: {fileID: 726788905} 446 | m_Layer: 0 447 | m_Name: GameObject 448 | m_TagString: Untagged 449 | m_Icon: {fileID: 0} 450 | m_NavMeshLayer: 0 451 | m_StaticEditorFlags: 0 452 | m_IsActive: 1 453 | --- !u!4 &726788905 454 | Transform: 455 | m_ObjectHideFlags: 0 456 | m_CorrespondingSourceObject: {fileID: 0} 457 | m_PrefabInstance: {fileID: 0} 458 | m_PrefabAsset: {fileID: 0} 459 | m_GameObject: {fileID: 726788904} 460 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 461 | m_LocalPosition: {x: 0, y: 0, z: 0} 462 | m_LocalScale: {x: 1, y: 1, z: 1} 463 | m_Children: [] 464 | m_Father: {fileID: 1667629376} 465 | m_RootOrder: 0 466 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 467 | --- !u!1 &800909437 468 | GameObject: 469 | m_ObjectHideFlags: 0 470 | m_CorrespondingSourceObject: {fileID: 0} 471 | m_PrefabInstance: {fileID: 0} 472 | m_PrefabAsset: {fileID: 0} 473 | serializedVersion: 6 474 | m_Component: 475 | - component: {fileID: 800909438} 476 | - component: {fileID: 800909439} 477 | m_Layer: 0 478 | m_Name: Folder (1) 479 | m_TagString: EditorOnly 480 | m_Icon: {fileID: 0} 481 | m_NavMeshLayer: 0 482 | m_StaticEditorFlags: 0 483 | m_IsActive: 1 484 | --- !u!4 &800909438 485 | Transform: 486 | m_ObjectHideFlags: 2 487 | m_CorrespondingSourceObject: {fileID: 0} 488 | m_PrefabInstance: {fileID: 0} 489 | m_PrefabAsset: {fileID: 0} 490 | m_GameObject: {fileID: 800909437} 491 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 492 | m_LocalPosition: {x: 0, y: 0, z: 0} 493 | m_LocalScale: {x: 1, y: 1, z: 1} 494 | m_Children: 495 | - {fileID: 1329040993} 496 | m_Father: {fileID: 1483094731} 497 | m_RootOrder: 1 498 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 499 | --- !u!114 &800909439 500 | MonoBehaviour: 501 | m_ObjectHideFlags: 0 502 | m_CorrespondingSourceObject: {fileID: 0} 503 | m_PrefabInstance: {fileID: 0} 504 | m_PrefabAsset: {fileID: 0} 505 | m_GameObject: {fileID: 800909437} 506 | m_Enabled: 1 507 | m_EditorHideFlags: 0 508 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 509 | m_Name: 510 | m_EditorClassIdentifier: 511 | _colorIndex: 0 512 | --- !u!1 &886383152 513 | GameObject: 514 | m_ObjectHideFlags: 0 515 | m_CorrespondingSourceObject: {fileID: 0} 516 | m_PrefabInstance: {fileID: 0} 517 | m_PrefabAsset: {fileID: 0} 518 | serializedVersion: 6 519 | m_Component: 520 | - component: {fileID: 886383154} 521 | - component: {fileID: 886383153} 522 | m_Layer: 0 523 | m_Name: isolated folder 524 | m_TagString: EditorOnly 525 | m_Icon: {fileID: 0} 526 | m_NavMeshLayer: 0 527 | m_StaticEditorFlags: 0 528 | m_IsActive: 1 529 | --- !u!114 &886383153 530 | MonoBehaviour: 531 | m_ObjectHideFlags: 0 532 | m_CorrespondingSourceObject: {fileID: 0} 533 | m_PrefabInstance: {fileID: 0} 534 | m_PrefabAsset: {fileID: 0} 535 | m_GameObject: {fileID: 886383152} 536 | m_Enabled: 1 537 | m_EditorHideFlags: 0 538 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 539 | m_Name: 540 | m_EditorClassIdentifier: 541 | _colorIndex: 0 542 | --- !u!4 &886383154 543 | Transform: 544 | m_ObjectHideFlags: 2 545 | m_CorrespondingSourceObject: {fileID: 0} 546 | m_PrefabInstance: {fileID: 0} 547 | m_PrefabAsset: {fileID: 0} 548 | m_GameObject: {fileID: 886383152} 549 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 550 | m_LocalPosition: {x: 0, y: 0, z: 0} 551 | m_LocalScale: {x: 1, y: 1, z: 1} 552 | m_Children: [] 553 | m_Father: {fileID: 0} 554 | m_RootOrder: 0 555 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 556 | --- !u!1 &895580445 557 | GameObject: 558 | m_ObjectHideFlags: 0 559 | m_CorrespondingSourceObject: {fileID: 0} 560 | m_PrefabInstance: {fileID: 0} 561 | m_PrefabAsset: {fileID: 0} 562 | serializedVersion: 6 563 | m_Component: 564 | - component: {fileID: 895580447} 565 | - component: {fileID: 895580446} 566 | m_Layer: 0 567 | m_Name: sibling folders in folder 568 | m_TagString: EditorOnly 569 | m_Icon: {fileID: 0} 570 | m_NavMeshLayer: 0 571 | m_StaticEditorFlags: 0 572 | m_IsActive: 1 573 | --- !u!114 &895580446 574 | MonoBehaviour: 575 | m_ObjectHideFlags: 0 576 | m_CorrespondingSourceObject: {fileID: 0} 577 | m_PrefabInstance: {fileID: 0} 578 | m_PrefabAsset: {fileID: 0} 579 | m_GameObject: {fileID: 895580445} 580 | m_Enabled: 1 581 | m_EditorHideFlags: 0 582 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 583 | m_Name: 584 | m_EditorClassIdentifier: 585 | _colorIndex: 6 586 | --- !u!4 &895580447 587 | Transform: 588 | m_ObjectHideFlags: 2 589 | m_CorrespondingSourceObject: {fileID: 0} 590 | m_PrefabInstance: {fileID: 0} 591 | m_PrefabAsset: {fileID: 0} 592 | m_GameObject: {fileID: 895580445} 593 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 594 | m_LocalPosition: {x: 0, y: 0, z: 0} 595 | m_LocalScale: {x: 1, y: 1, z: 1} 596 | m_Children: 597 | - {fileID: 1536283074} 598 | - {fileID: 1114720478} 599 | - {fileID: 290315315} 600 | m_Father: {fileID: 0} 601 | m_RootOrder: 6 602 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 603 | --- !u!1 &973126717 604 | GameObject: 605 | m_ObjectHideFlags: 0 606 | m_CorrespondingSourceObject: {fileID: 0} 607 | m_PrefabInstance: {fileID: 0} 608 | m_PrefabAsset: {fileID: 0} 609 | serializedVersion: 6 610 | m_Component: 611 | - component: {fileID: 973126718} 612 | - component: {fileID: 973126719} 613 | m_Layer: 0 614 | m_Name: Folder 615 | m_TagString: EditorOnly 616 | m_Icon: {fileID: 0} 617 | m_NavMeshLayer: 0 618 | m_StaticEditorFlags: 0 619 | m_IsActive: 1 620 | --- !u!4 &973126718 621 | Transform: 622 | m_ObjectHideFlags: 2 623 | m_CorrespondingSourceObject: {fileID: 0} 624 | m_PrefabInstance: {fileID: 0} 625 | m_PrefabAsset: {fileID: 0} 626 | m_GameObject: {fileID: 973126717} 627 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 628 | m_LocalPosition: {x: 0, y: 0, z: 0} 629 | m_LocalScale: {x: 1, y: 1, z: 1} 630 | m_Children: [] 631 | m_Father: {fileID: 1483094731} 632 | m_RootOrder: 0 633 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 634 | --- !u!114 &973126719 635 | MonoBehaviour: 636 | m_ObjectHideFlags: 0 637 | m_CorrespondingSourceObject: {fileID: 0} 638 | m_PrefabInstance: {fileID: 0} 639 | m_PrefabAsset: {fileID: 0} 640 | m_GameObject: {fileID: 973126717} 641 | m_Enabled: 1 642 | m_EditorHideFlags: 0 643 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 644 | m_Name: 645 | m_EditorClassIdentifier: 646 | _colorIndex: 0 647 | --- !u!1 &1114720477 648 | GameObject: 649 | m_ObjectHideFlags: 0 650 | m_CorrespondingSourceObject: {fileID: 0} 651 | m_PrefabInstance: {fileID: 0} 652 | m_PrefabAsset: {fileID: 0} 653 | serializedVersion: 6 654 | m_Component: 655 | - component: {fileID: 1114720478} 656 | - component: {fileID: 1114720479} 657 | m_Layer: 0 658 | m_Name: Folder (2) 659 | m_TagString: EditorOnly 660 | m_Icon: {fileID: 0} 661 | m_NavMeshLayer: 0 662 | m_StaticEditorFlags: 0 663 | m_IsActive: 1 664 | --- !u!4 &1114720478 665 | Transform: 666 | m_ObjectHideFlags: 2 667 | m_CorrespondingSourceObject: {fileID: 0} 668 | m_PrefabInstance: {fileID: 0} 669 | m_PrefabAsset: {fileID: 0} 670 | m_GameObject: {fileID: 1114720477} 671 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 672 | m_LocalPosition: {x: 0, y: 0, z: 0} 673 | m_LocalScale: {x: 1, y: 1, z: 1} 674 | m_Children: [] 675 | m_Father: {fileID: 895580447} 676 | m_RootOrder: 1 677 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 678 | --- !u!114 &1114720479 679 | MonoBehaviour: 680 | m_ObjectHideFlags: 0 681 | m_CorrespondingSourceObject: {fileID: 0} 682 | m_PrefabInstance: {fileID: 0} 683 | m_PrefabAsset: {fileID: 0} 684 | m_GameObject: {fileID: 1114720477} 685 | m_Enabled: 1 686 | m_EditorHideFlags: 0 687 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 688 | m_Name: 689 | m_EditorClassIdentifier: 690 | _colorIndex: 0 691 | --- !u!1 &1131533462 692 | GameObject: 693 | m_ObjectHideFlags: 0 694 | m_CorrespondingSourceObject: {fileID: 0} 695 | m_PrefabInstance: {fileID: 0} 696 | m_PrefabAsset: {fileID: 0} 697 | serializedVersion: 6 698 | m_Component: 699 | - component: {fileID: 1131533464} 700 | - component: {fileID: 1131533463} 701 | m_Layer: 0 702 | m_Name: indirectly full folder 703 | m_TagString: EditorOnly 704 | m_Icon: {fileID: 0} 705 | m_NavMeshLayer: 0 706 | m_StaticEditorFlags: 0 707 | m_IsActive: 1 708 | --- !u!114 &1131533463 709 | MonoBehaviour: 710 | m_ObjectHideFlags: 0 711 | m_CorrespondingSourceObject: {fileID: 0} 712 | m_PrefabInstance: {fileID: 0} 713 | m_PrefabAsset: {fileID: 0} 714 | m_GameObject: {fileID: 1131533462} 715 | m_Enabled: 1 716 | m_EditorHideFlags: 0 717 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 718 | m_Name: 719 | m_EditorClassIdentifier: 720 | _colorIndex: 3 721 | --- !u!4 &1131533464 722 | Transform: 723 | m_ObjectHideFlags: 2 724 | m_CorrespondingSourceObject: {fileID: 0} 725 | m_PrefabInstance: {fileID: 0} 726 | m_PrefabAsset: {fileID: 0} 727 | m_GameObject: {fileID: 1131533462} 728 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 729 | m_LocalPosition: {x: 0, y: 0, z: 0} 730 | m_LocalScale: {x: 1, y: 1, z: 1} 731 | m_Children: 732 | - {fileID: 526939266} 733 | m_Father: {fileID: 0} 734 | m_RootOrder: 3 735 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 736 | --- !u!1 &1329040992 737 | GameObject: 738 | m_ObjectHideFlags: 0 739 | m_CorrespondingSourceObject: {fileID: 0} 740 | m_PrefabInstance: {fileID: 0} 741 | m_PrefabAsset: {fileID: 0} 742 | serializedVersion: 6 743 | m_Component: 744 | - component: {fileID: 1329040993} 745 | m_Layer: 0 746 | m_Name: GameObject 747 | m_TagString: Untagged 748 | m_Icon: {fileID: 0} 749 | m_NavMeshLayer: 0 750 | m_StaticEditorFlags: 0 751 | m_IsActive: 1 752 | --- !u!4 &1329040993 753 | Transform: 754 | m_ObjectHideFlags: 0 755 | m_CorrespondingSourceObject: {fileID: 0} 756 | m_PrefabInstance: {fileID: 0} 757 | m_PrefabAsset: {fileID: 0} 758 | m_GameObject: {fileID: 1329040992} 759 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 760 | m_LocalPosition: {x: 0, y: 0, z: 0} 761 | m_LocalScale: {x: 1, y: 1, z: 1} 762 | m_Children: [] 763 | m_Father: {fileID: 800909438} 764 | m_RootOrder: 0 765 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 766 | --- !u!1 &1378523846 767 | GameObject: 768 | m_ObjectHideFlags: 0 769 | m_CorrespondingSourceObject: {fileID: 0} 770 | m_PrefabInstance: {fileID: 0} 771 | m_PrefabAsset: {fileID: 0} 772 | serializedVersion: 6 773 | m_Component: 774 | - component: {fileID: 1378523847} 775 | m_Layer: 0 776 | m_Name: g 777 | m_TagString: Untagged 778 | m_Icon: {fileID: 0} 779 | m_NavMeshLayer: 0 780 | m_StaticEditorFlags: 0 781 | m_IsActive: 1 782 | --- !u!4 &1378523847 783 | Transform: 784 | m_ObjectHideFlags: 0 785 | m_CorrespondingSourceObject: {fileID: 0} 786 | m_PrefabInstance: {fileID: 0} 787 | m_PrefabAsset: {fileID: 0} 788 | m_GameObject: {fileID: 1378523846} 789 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 790 | m_LocalPosition: {x: 0, y: 0, z: 0} 791 | m_LocalScale: {x: 1, y: 1, z: 1} 792 | m_Children: [] 793 | m_Father: {fileID: 1694949953} 794 | m_RootOrder: 2 795 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 796 | --- !u!1 &1436896066 797 | GameObject: 798 | m_ObjectHideFlags: 0 799 | m_CorrespondingSourceObject: {fileID: 0} 800 | m_PrefabInstance: {fileID: 0} 801 | m_PrefabAsset: {fileID: 0} 802 | serializedVersion: 6 803 | m_Component: 804 | - component: {fileID: 1436896067} 805 | m_Layer: 0 806 | m_Name: e 807 | m_TagString: Untagged 808 | m_Icon: {fileID: 0} 809 | m_NavMeshLayer: 0 810 | m_StaticEditorFlags: 0 811 | m_IsActive: 1 812 | --- !u!4 &1436896067 813 | Transform: 814 | m_ObjectHideFlags: 0 815 | m_CorrespondingSourceObject: {fileID: 0} 816 | m_PrefabInstance: {fileID: 0} 817 | m_PrefabAsset: {fileID: 0} 818 | m_GameObject: {fileID: 1436896066} 819 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 820 | m_LocalPosition: {x: 0, y: 0, z: 0} 821 | m_LocalScale: {x: 1, y: 1, z: 1} 822 | m_Children: [] 823 | m_Father: {fileID: 1694949953} 824 | m_RootOrder: 0 825 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 826 | --- !u!1 &1483094730 827 | GameObject: 828 | m_ObjectHideFlags: 0 829 | m_CorrespondingSourceObject: {fileID: 0} 830 | m_PrefabInstance: {fileID: 0} 831 | m_PrefabAsset: {fileID: 0} 832 | serializedVersion: 6 833 | m_Component: 834 | - component: {fileID: 1483094731} 835 | m_Layer: 0 836 | m_Name: GameObject (1) 837 | m_TagString: Untagged 838 | m_Icon: {fileID: 0} 839 | m_NavMeshLayer: 0 840 | m_StaticEditorFlags: 0 841 | m_IsActive: 1 842 | --- !u!4 &1483094731 843 | Transform: 844 | m_ObjectHideFlags: 0 845 | m_CorrespondingSourceObject: {fileID: 0} 846 | m_PrefabInstance: {fileID: 0} 847 | m_PrefabAsset: {fileID: 0} 848 | m_GameObject: {fileID: 1483094730} 849 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 850 | m_LocalPosition: {x: 0, y: 0, z: 0} 851 | m_LocalScale: {x: 1, y: 1, z: 1} 852 | m_Children: 853 | - {fileID: 973126718} 854 | - {fileID: 800909438} 855 | m_Father: {fileID: 1667629376} 856 | m_RootOrder: 1 857 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 858 | --- !u!1 &1536283073 859 | GameObject: 860 | m_ObjectHideFlags: 0 861 | m_CorrespondingSourceObject: {fileID: 0} 862 | m_PrefabInstance: {fileID: 0} 863 | m_PrefabAsset: {fileID: 0} 864 | serializedVersion: 6 865 | m_Component: 866 | - component: {fileID: 1536283074} 867 | - component: {fileID: 1536283075} 868 | m_Layer: 0 869 | m_Name: Folder (1) 870 | m_TagString: EditorOnly 871 | m_Icon: {fileID: 0} 872 | m_NavMeshLayer: 0 873 | m_StaticEditorFlags: 0 874 | m_IsActive: 1 875 | --- !u!4 &1536283074 876 | Transform: 877 | m_ObjectHideFlags: 2 878 | m_CorrespondingSourceObject: {fileID: 0} 879 | m_PrefabInstance: {fileID: 0} 880 | m_PrefabAsset: {fileID: 0} 881 | m_GameObject: {fileID: 1536283073} 882 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 883 | m_LocalPosition: {x: 0, y: 0, z: 0} 884 | m_LocalScale: {x: 1, y: 1, z: 1} 885 | m_Children: [] 886 | m_Father: {fileID: 895580447} 887 | m_RootOrder: 0 888 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 889 | --- !u!114 &1536283075 890 | MonoBehaviour: 891 | m_ObjectHideFlags: 0 892 | m_CorrespondingSourceObject: {fileID: 0} 893 | m_PrefabInstance: {fileID: 0} 894 | m_PrefabAsset: {fileID: 0} 895 | m_GameObject: {fileID: 1536283073} 896 | m_Enabled: 1 897 | m_EditorHideFlags: 0 898 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 899 | m_Name: 900 | m_EditorClassIdentifier: 901 | _colorIndex: 0 902 | --- !u!1 &1547221050 903 | GameObject: 904 | m_ObjectHideFlags: 0 905 | m_CorrespondingSourceObject: {fileID: 0} 906 | m_PrefabInstance: {fileID: 0} 907 | m_PrefabAsset: {fileID: 0} 908 | serializedVersion: 6 909 | m_Component: 910 | - component: {fileID: 1547221051} 911 | m_Layer: 0 912 | m_Name: i 913 | m_TagString: Untagged 914 | m_Icon: {fileID: 0} 915 | m_NavMeshLayer: 0 916 | m_StaticEditorFlags: 0 917 | m_IsActive: 1 918 | --- !u!4 &1547221051 919 | Transform: 920 | m_ObjectHideFlags: 0 921 | m_CorrespondingSourceObject: {fileID: 0} 922 | m_PrefabInstance: {fileID: 0} 923 | m_PrefabAsset: {fileID: 0} 924 | m_GameObject: {fileID: 1547221050} 925 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 926 | m_LocalPosition: {x: 0, y: 0, z: 0} 927 | m_LocalScale: {x: 1, y: 1, z: 1} 928 | m_Children: [] 929 | m_Father: {fileID: 1831796945} 930 | m_RootOrder: 0 931 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 932 | --- !u!1 &1641000843 933 | GameObject: 934 | m_ObjectHideFlags: 0 935 | m_CorrespondingSourceObject: {fileID: 0} 936 | m_PrefabInstance: {fileID: 0} 937 | m_PrefabAsset: {fileID: 0} 938 | serializedVersion: 6 939 | m_Component: 940 | - component: {fileID: 1641000844} 941 | m_Layer: 0 942 | m_Name: d 943 | m_TagString: Untagged 944 | m_Icon: {fileID: 0} 945 | m_NavMeshLayer: 0 946 | m_StaticEditorFlags: 0 947 | m_IsActive: 1 948 | --- !u!4 &1641000844 949 | Transform: 950 | m_ObjectHideFlags: 0 951 | m_CorrespondingSourceObject: {fileID: 0} 952 | m_PrefabInstance: {fileID: 0} 953 | m_PrefabAsset: {fileID: 0} 954 | m_GameObject: {fileID: 1641000843} 955 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 956 | m_LocalPosition: {x: 0, y: 0, z: 0} 957 | m_LocalScale: {x: 1, y: 1, z: 1} 958 | m_Children: [] 959 | m_Father: {fileID: 1739973907} 960 | m_RootOrder: 1 961 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 962 | --- !u!1 &1667629375 963 | GameObject: 964 | m_ObjectHideFlags: 0 965 | m_CorrespondingSourceObject: {fileID: 0} 966 | m_PrefabInstance: {fileID: 0} 967 | m_PrefabAsset: {fileID: 0} 968 | serializedVersion: 6 969 | m_Component: 970 | - component: {fileID: 1667629376} 971 | - component: {fileID: 1667629377} 972 | m_Layer: 0 973 | m_Name: Folder 974 | m_TagString: EditorOnly 975 | m_Icon: {fileID: 0} 976 | m_NavMeshLayer: 0 977 | m_StaticEditorFlags: 0 978 | m_IsActive: 1 979 | --- !u!4 &1667629376 980 | Transform: 981 | m_ObjectHideFlags: 2 982 | m_CorrespondingSourceObject: {fileID: 0} 983 | m_PrefabInstance: {fileID: 0} 984 | m_PrefabAsset: {fileID: 0} 985 | m_GameObject: {fileID: 1667629375} 986 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 987 | m_LocalPosition: {x: 0, y: 0, z: 0} 988 | m_LocalScale: {x: 1, y: 1, z: 1} 989 | m_Children: 990 | - {fileID: 726788905} 991 | - {fileID: 1483094731} 992 | m_Father: {fileID: 1831796945} 993 | m_RootOrder: 1 994 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 995 | --- !u!114 &1667629377 996 | MonoBehaviour: 997 | m_ObjectHideFlags: 0 998 | m_CorrespondingSourceObject: {fileID: 0} 999 | m_PrefabInstance: {fileID: 0} 1000 | m_PrefabAsset: {fileID: 0} 1001 | m_GameObject: {fileID: 1667629375} 1002 | m_Enabled: 1 1003 | m_EditorHideFlags: 0 1004 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 1005 | m_Name: 1006 | m_EditorClassIdentifier: 1007 | _colorIndex: 0 1008 | --- !u!1 &1679747511 1009 | GameObject: 1010 | m_ObjectHideFlags: 0 1011 | m_CorrespondingSourceObject: {fileID: 0} 1012 | m_PrefabInstance: {fileID: 0} 1013 | m_PrefabAsset: {fileID: 0} 1014 | serializedVersion: 6 1015 | m_Component: 1016 | - component: {fileID: 1679747512} 1017 | m_Layer: 0 1018 | m_Name: c 1019 | m_TagString: Untagged 1020 | m_Icon: {fileID: 0} 1021 | m_NavMeshLayer: 0 1022 | m_StaticEditorFlags: 0 1023 | m_IsActive: 1 1024 | --- !u!4 &1679747512 1025 | Transform: 1026 | m_ObjectHideFlags: 0 1027 | m_CorrespondingSourceObject: {fileID: 0} 1028 | m_PrefabInstance: {fileID: 0} 1029 | m_PrefabAsset: {fileID: 0} 1030 | m_GameObject: {fileID: 1679747511} 1031 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 1032 | m_LocalPosition: {x: 0, y: 0, z: 0} 1033 | m_LocalScale: {x: 1, y: 1, z: 1} 1034 | m_Children: [] 1035 | m_Father: {fileID: 1739973907} 1036 | m_RootOrder: 0 1037 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1038 | --- !u!1 &1694949951 1039 | GameObject: 1040 | m_ObjectHideFlags: 0 1041 | m_CorrespondingSourceObject: {fileID: 0} 1042 | m_PrefabInstance: {fileID: 0} 1043 | m_PrefabAsset: {fileID: 0} 1044 | serializedVersion: 6 1045 | m_Component: 1046 | - component: {fileID: 1694949953} 1047 | - component: {fileID: 1694949952} 1048 | m_Layer: 0 1049 | m_Name: sibling items in folder (1) 1050 | m_TagString: EditorOnly 1051 | m_Icon: {fileID: 0} 1052 | m_NavMeshLayer: 0 1053 | m_StaticEditorFlags: 0 1054 | m_IsActive: 1 1055 | --- !u!114 &1694949952 1056 | MonoBehaviour: 1057 | m_ObjectHideFlags: 0 1058 | m_CorrespondingSourceObject: {fileID: 0} 1059 | m_PrefabInstance: {fileID: 0} 1060 | m_PrefabAsset: {fileID: 0} 1061 | m_GameObject: {fileID: 1694949951} 1062 | m_Enabled: 1 1063 | m_EditorHideFlags: 0 1064 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 1065 | m_Name: 1066 | m_EditorClassIdentifier: 1067 | _colorIndex: 5 1068 | --- !u!4 &1694949953 1069 | Transform: 1070 | m_ObjectHideFlags: 2 1071 | m_CorrespondingSourceObject: {fileID: 0} 1072 | m_PrefabInstance: {fileID: 0} 1073 | m_PrefabAsset: {fileID: 0} 1074 | m_GameObject: {fileID: 1694949951} 1075 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 1076 | m_LocalPosition: {x: 0, y: 0, z: 0} 1077 | m_LocalScale: {x: 1, y: 1, z: 1} 1078 | m_Children: 1079 | - {fileID: 1436896067} 1080 | - {fileID: 132138652} 1081 | - {fileID: 1378523847} 1082 | - {fileID: 450170594} 1083 | m_Father: {fileID: 0} 1084 | m_RootOrder: 5 1085 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1086 | --- !u!1 &1739973905 1087 | GameObject: 1088 | m_ObjectHideFlags: 0 1089 | m_CorrespondingSourceObject: {fileID: 0} 1090 | m_PrefabInstance: {fileID: 0} 1091 | m_PrefabAsset: {fileID: 0} 1092 | serializedVersion: 6 1093 | m_Component: 1094 | - component: {fileID: 1739973907} 1095 | - component: {fileID: 1739973906} 1096 | m_Layer: 0 1097 | m_Name: sibling items in folder 1098 | m_TagString: EditorOnly 1099 | m_Icon: {fileID: 0} 1100 | m_NavMeshLayer: 0 1101 | m_StaticEditorFlags: 0 1102 | m_IsActive: 1 1103 | --- !u!114 &1739973906 1104 | MonoBehaviour: 1105 | m_ObjectHideFlags: 0 1106 | m_CorrespondingSourceObject: {fileID: 0} 1107 | m_PrefabInstance: {fileID: 0} 1108 | m_PrefabAsset: {fileID: 0} 1109 | m_GameObject: {fileID: 1739973905} 1110 | m_Enabled: 1 1111 | m_EditorHideFlags: 0 1112 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 1113 | m_Name: 1114 | m_EditorClassIdentifier: 1115 | _colorIndex: 4 1116 | --- !u!4 &1739973907 1117 | Transform: 1118 | m_ObjectHideFlags: 2 1119 | m_CorrespondingSourceObject: {fileID: 0} 1120 | m_PrefabInstance: {fileID: 0} 1121 | m_PrefabAsset: {fileID: 0} 1122 | m_GameObject: {fileID: 1739973905} 1123 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 1124 | m_LocalPosition: {x: 0, y: 0, z: 0} 1125 | m_LocalScale: {x: 1, y: 1, z: 1} 1126 | m_Children: 1127 | - {fileID: 1679747512} 1128 | - {fileID: 1641000844} 1129 | m_Father: {fileID: 0} 1130 | m_RootOrder: 4 1131 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1132 | --- !u!1 &1773556886 1133 | GameObject: 1134 | m_ObjectHideFlags: 0 1135 | m_CorrespondingSourceObject: {fileID: 0} 1136 | m_PrefabInstance: {fileID: 0} 1137 | m_PrefabAsset: {fileID: 0} 1138 | serializedVersion: 6 1139 | m_Component: 1140 | - component: {fileID: 1773556887} 1141 | - component: {fileID: 1773556888} 1142 | m_Layer: 0 1143 | m_Name: direct sublevel folder 1144 | m_TagString: EditorOnly 1145 | m_Icon: {fileID: 0} 1146 | m_NavMeshLayer: 0 1147 | m_StaticEditorFlags: 0 1148 | m_IsActive: 1 1149 | --- !u!4 &1773556887 1150 | Transform: 1151 | m_ObjectHideFlags: 2 1152 | m_CorrespondingSourceObject: {fileID: 0} 1153 | m_PrefabInstance: {fileID: 0} 1154 | m_PrefabAsset: {fileID: 0} 1155 | m_GameObject: {fileID: 1773556886} 1156 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1157 | m_LocalPosition: {x: 0, y: 0, z: 0} 1158 | m_LocalScale: {x: 1, y: 1, z: 1} 1159 | m_Children: [] 1160 | m_Father: {fileID: 607056355} 1161 | m_RootOrder: 0 1162 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1163 | --- !u!114 &1773556888 1164 | MonoBehaviour: 1165 | m_ObjectHideFlags: 0 1166 | m_CorrespondingSourceObject: {fileID: 0} 1167 | m_PrefabInstance: {fileID: 0} 1168 | m_PrefabAsset: {fileID: 0} 1169 | m_GameObject: {fileID: 1773556886} 1170 | m_Enabled: 1 1171 | m_EditorHideFlags: 0 1172 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 1173 | m_Name: 1174 | m_EditorClassIdentifier: 1175 | _colorIndex: 0 1176 | --- !u!1 &1831796943 1177 | GameObject: 1178 | m_ObjectHideFlags: 0 1179 | m_CorrespondingSourceObject: {fileID: 0} 1180 | m_PrefabInstance: {fileID: 0} 1181 | m_PrefabAsset: {fileID: 0} 1182 | serializedVersion: 6 1183 | m_Component: 1184 | - component: {fileID: 1831796945} 1185 | - component: {fileID: 1831796944} 1186 | m_Layer: 0 1187 | m_Name: all together now 1188 | m_TagString: EditorOnly 1189 | m_Icon: {fileID: 0} 1190 | m_NavMeshLayer: 0 1191 | m_StaticEditorFlags: 0 1192 | m_IsActive: 1 1193 | --- !u!114 &1831796944 1194 | MonoBehaviour: 1195 | m_ObjectHideFlags: 0 1196 | m_CorrespondingSourceObject: {fileID: 0} 1197 | m_PrefabInstance: {fileID: 0} 1198 | m_PrefabAsset: {fileID: 0} 1199 | m_GameObject: {fileID: 1831796943} 1200 | m_Enabled: 1 1201 | m_EditorHideFlags: 0 1202 | m_Script: {fileID: 11500000, guid: 149818d5acbed4455af27721dc46461a, type: 3} 1203 | m_Name: 1204 | m_EditorClassIdentifier: 1205 | _colorIndex: 7 1206 | --- !u!4 &1831796945 1207 | Transform: 1208 | m_ObjectHideFlags: 2 1209 | m_CorrespondingSourceObject: {fileID: 0} 1210 | m_PrefabInstance: {fileID: 0} 1211 | m_PrefabAsset: {fileID: 0} 1212 | m_GameObject: {fileID: 1831796943} 1213 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 1214 | m_LocalPosition: {x: 0, y: 0, z: 0} 1215 | m_LocalScale: {x: 1, y: 1, z: 1} 1216 | m_Children: 1217 | - {fileID: 1547221051} 1218 | - {fileID: 1667629376} 1219 | - {fileID: 237864227} 1220 | m_Father: {fileID: 0} 1221 | m_RootOrder: 7 1222 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1223 | --- !u!1 &2052390213 1224 | GameObject: 1225 | m_ObjectHideFlags: 0 1226 | m_CorrespondingSourceObject: {fileID: 0} 1227 | m_PrefabInstance: {fileID: 0} 1228 | m_PrefabAsset: {fileID: 0} 1229 | serializedVersion: 6 1230 | m_Component: 1231 | - component: {fileID: 2052390214} 1232 | m_Layer: 0 1233 | m_Name: b 1234 | m_TagString: Untagged 1235 | m_Icon: {fileID: 0} 1236 | m_NavMeshLayer: 0 1237 | m_StaticEditorFlags: 0 1238 | m_IsActive: 1 1239 | --- !u!4 &2052390214 1240 | Transform: 1241 | m_ObjectHideFlags: 0 1242 | m_CorrespondingSourceObject: {fileID: 0} 1243 | m_PrefabInstance: {fileID: 0} 1244 | m_PrefabAsset: {fileID: 0} 1245 | m_GameObject: {fileID: 2052390213} 1246 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 1247 | m_LocalPosition: {x: 0, y: 0, z: 0} 1248 | m_LocalScale: {x: 1, y: 1, z: 1} 1249 | m_Children: [] 1250 | m_Father: {fileID: 526939266} 1251 | m_RootOrder: 0 1252 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1253 | -------------------------------------------------------------------------------- /Tests/Example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 941414e4905aa48b68ef3e9d24d0ddd5 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.xsduan.hierarchy-folders", 3 | "displayName": "Hierarchy Folders", 4 | "version": "0.3.1", 5 | "unity": "2018.1", 6 | "description": "Self-deleting Folder objects for the heirarchy.", 7 | "keywords": [ 8 | "folder", 9 | "organization", 10 | "unity" 11 | ], 12 | "author": { 13 | "name": "Shane Duan" 14 | }, 15 | "category": "Unity", 16 | "dependencies": { 17 | "com.unity.settings-manager": "1.0.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 962ff8039b1cb476983eb345ca5ddfdd 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------