internal void AddAsset(AssetObjectInfo assetInfo) { if (AssetList == null) AssetList = new List<AssetObjectInfo>(); assetInfo.SetParent(this); AssetList.Add(assetInfo); }
internal void AddAsset(AssetObjectInfo assetInfo) { if (AssetList == null) { AssetList = new List <AssetObjectInfo>(); } assetInfo.SetParent(this); AssetList.Add(assetInfo); }
private void drawAssetFolderInfoRecursively(ProjectFolderInfo assetFolder, int indentLevel) { EditorGUI.indentLevel = indentLevel; if (!assetFolder.ShouldBeListed(m_unusedTypeDict)) return; else { int assetCount = assetFolder.GetAssetCountInChildren(); EditorGUILayout.BeginHorizontal(); Color initialColor = GUI.color; GUI.color = Color.yellow; float buttonSizeSelect = 60; float buttonSizeDelete = 100; if (GUILayout.Button("Delete all " + assetCount, GUILayout.Width(buttonSizeDelete))) { m_folderMarkedForDeletion = assetFolder; } //Add space to align UI elements GUILayout.Space(buttonSizeSelect); //Create new style to have a bold foldout GUIStyle style = EditorStyles.foldout; FontStyle previousStyle = style.fontStyle; style.fontStyle = FontStyle.Bold; //Show foldout assetFolder.FoldOut = EditorGUILayout.Foldout(assetFolder.FoldOut, assetFolder.DirectoryName + " (" + assetCount + ")", style); //Reset style style.fontStyle = previousStyle; //Reset color GUI.color = initialColor; EditorGUILayout.EndHorizontal(); if (assetFolder.FoldOut) { foreach (AssetObjectInfo aInfo in assetFolder.AssetList) { if ((m_unusedTypeDict.ContainsKey(aInfo.m_Type) && m_unusedTypeDict[aInfo.m_Type] == false)) continue; EditorGUI.indentLevel = (indentLevel + 1); EditorGUILayout.BeginHorizontal(); GUI.color = Color.grey; if (GUILayout.Button("Delete", GUILayout.Width(buttonSizeDelete))) { m_assetMarkedForDeletion = aInfo; } GUI.color = initialColor; if (GUILayout.Button("Select", GUILayout.Width(buttonSizeSelect))) { Selection.activeObject = AssetDatabase.LoadAssetAtPath(aInfo.m_Path, aInfo.m_Type.SystemType); } EditorGUILayout.LabelField(aInfo.m_Name, GUILayout.MaxWidth(600)); EditorGUILayout.EndHorizontal(); } foreach (int childFolder in assetFolder.ChildFolderIndexers) { drawAssetFolderInfoRecursively(m_ProjectFolderList[childFolder], (indentLevel + 1)); } } } }
private void showUnusedAssets() { EditorGUILayout.Separator(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Collapse All", GUILayout.Width(btnMinWidth))) { foreach (ProjectFolderInfo folder in m_ProjectFolderList) { folder.FoldOut = false; } } EditorGUILayout.Space(); if (GUILayout.Button("Expand All", GUILayout.Width(btnMinWidth))) { foreach (ProjectFolderInfo folder in m_ProjectFolderList) { folder.FoldOut = true; } } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); EditorGUILayout.Separator(); int indentLevel = 0; drawAssetFolderInfoRecursively(m_ProjectFolderList[0], indentLevel); if (m_assetMarkedForDeletion != null) { if (EditorUtility.DisplayDialog("Delete asset", "Are you sure you want to delete " + m_assetMarkedForDeletion.m_Name, "Yes", "No")) { m_assetMarkedForDeletion.Delete(m_unusedTypeDict); //Delete potential empty folders processDirectory(getSystemFolderPath(m_assetMarkedForDeletion.m_ParentPath)); m_assetMarkedForDeletion = null; } else m_assetMarkedForDeletion = null; } else if (m_folderMarkedForDeletion != null) { if (EditorUtility.DisplayDialog("Delete all assets in folder", "Are you sure you want to delete all " + m_folderMarkedForDeletion.GetAssetCountInChildren() + " assets in: " + m_folderMarkedForDeletion.DirectoryName, "Yes", "No")) { List<AssetObjectInfo> objectsToDelete = new List<AssetObjectInfo>(); getObjectsMarkedForDeletion(m_folderMarkedForDeletion, ref objectsToDelete); deleteSelected(objectsToDelete); //Delete potential empty folders processDirectory(getSystemFolderPath(m_folderMarkedForDeletion.DirectoryName)); m_folderMarkedForDeletion = null; refreshUnusedAssets(); } else { m_folderMarkedForDeletion = null; } } }
private static void traverseDirectory(int parentIndex, string path, List <BuildReportAsset> usedAssets, int heirarchyDepth, ref int directoriesTraversed, SortedDictionary <SerializableSystemType, bool> validTypeList) { directoriesTraversed++; EditorUtility.DisplayProgressBar( "Traversing Directories", "(" + directoriesTraversed + " of " + m_NumberOfDirectories + ") Analyzing " + path.Substring(path.IndexOf("/Assets") + 1), (float)directoriesTraversed / (float)m_NumberOfDirectories); //Get the settings to exclude vertain folders or suffixes foreach (UnityEngine.Object dir in AssetHunterMainWindow.Instance.settings.m_DirectoryExcludes) { //TODO Can this be done more elegantly int startingIndex = Application.dataPath.Length - 6; string relativePath = path.Substring(startingIndex, path.Length - startingIndex); UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(relativePath, typeof(UnityEngine.Object)); if (dir == obj) { //This folder was exluded return; } } string[] assetsInDirectory = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly) .Where(name => !name.ToLowerInvariant().EndsWith(".meta") && (!name.ToLowerInvariant().EndsWith(".unity")) && (!name.ToLowerInvariant().EndsWith("thumbs.db")) && (!name.ToLowerInvariant().EndsWith(".orig")) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "heureka" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "plugins" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "streamingassets" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor default resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(@".ds_store")) && (!name.ToLowerInvariant().Contains(@".workspace.mel")) && (!name.ToLowerInvariant().Contains(@".mayaswatches"))) .ToArray(); for (int i = 0; i < assetsInDirectory.Length; i++) { assetsInDirectory[i] = assetsInDirectory[i].Substring(assetsInDirectory[i].IndexOf("/Assets") + 1); assetsInDirectory[i] = assetsInDirectory[i].Replace(@"\", "/"); } //Find any assets that does not live in UsedAssets List var result = assetsInDirectory.Where(p => !usedAssets.Any(p2 => UnityEditor.AssetDatabase.GUIDToAssetPath(p2.GUID) == p)); //Create new folder object ProjectFolderInfo afInfo = new ProjectFolderInfo(); afInfo.DirectoryName = path.Substring(path.IndexOf("/Assets") + 1).Replace(@"\", "/"); afInfo.ParentIndex = parentIndex; if (heirarchyDepth == 0) { afInfo.FoldOut = true; } //Add to static list AssetHunterMainWindow.Instance.AddProjectFolderInfo(afInfo); if (parentIndex != -1) { AssetHunterMainWindow.Instance.GetFolderList()[parentIndex].AddChildFolder(afInfo); } UnityEngine.Object objToFind; foreach (string assetName in result) { objToFind = AssetDatabase.LoadAssetAtPath(assetName, typeof(UnityEngine.Object)); if (objToFind == null) { Debug.LogWarning("Couldnt find " + assetName); continue; } SerializableSystemType assetType = new SerializableSystemType(objToFind.GetType()); if (assetType.SystemType != typeof(MonoScript) && (!AssetHunterMainWindow.Instance.settings.m_AssetTypeExcludes.Contains(assetType))) { AssetObjectInfo newAssetInfo = new AssetObjectInfo(assetName, assetType); afInfo.AddAsset(newAssetInfo); } objToFind = null; //Memory leak safeguard UnloadUnused(); } string[] nextLevelDirectories = System.IO.Directory.GetDirectories(path, "*.*", System.IO.SearchOption.TopDirectoryOnly); foreach (string nld in nextLevelDirectories) { traverseDirectory(AssetHunterMainWindow.Instance.GetFolderList().IndexOf(afInfo), nld, usedAssets, (heirarchyDepth + 1), ref directoriesTraversed, validTypeList); } }
internal void RemoveAsset(AssetObjectInfo assetObjectInfo) { m_assetList.Remove(assetObjectInfo); }
public void OnAfterDeserialize() { m_folderMarkedForDeletion = null; m_assetMarkedForDeletion = null; m_unusedTypeDict.Clear(); for (int i = 0; i != Mathf.Min(m_unusedTypeListKeysSerializer.Count, m_unusedTypeListValuesSerializer.Count); i++) { m_unusedTypeDict.Add(m_unusedTypeListKeysSerializer[i], m_unusedTypeListValuesSerializer[i]); } m_usedTypeDict.Clear(); for (int i = 0; i != Mathf.Min(m_usedTypeListKeysSerializer.Count, m_usedTypeListValuesSerializer.Count); i++) { m_usedTypeDict.Add(m_usedTypeListKeysSerializer[i], m_usedTypeListValuesSerializer[i]); } m_assetSceneDependencies.Clear(); for (int i = 0; i != Mathf.Min(m_assetSceneDependencyKeysSerializer.Count, m_assetSceneDependencyValueSerializer.Count); i++) { m_assetSceneDependencies.Add(m_assetSceneDependencyKeysSerializer[i], m_assetSceneDependencyValueSerializer[i].list); } }
private static void traverseDirectory(int parentIndex, string path, List<BuildReportAsset> usedAssets, int heirarchyDepth, ref int directoriesTraversed, SortedDictionary<SerializableSystemType, bool> validTypeList) { directoriesTraversed++; EditorUtility.DisplayProgressBar( "Traversing Directories", "(" + directoriesTraversed + " of " + m_NumberOfDirectories + ") Analyzing " + path.Substring(path.IndexOf("/Assets") + 1), (float)directoriesTraversed / (float)m_NumberOfDirectories); //Get the settings to exclude vertain folders or suffixes foreach (UnityEngine.Object dir in AssetHunterMainWindow.Instance.settings.m_DirectoryExcludes) { //TODO Can this be done more elegantly int startingIndex = Application.dataPath.Length - 6; string relativePath = path.Substring(startingIndex, path.Length - startingIndex); UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(relativePath, typeof(UnityEngine.Object)); if (dir == obj) { //This folder was exluded return; } } //Exclude types and folders that should not be reviewed //TODO perhaps improve performance of this step (Also use String.Contains(excluder, StringComparison.OrdinalIgnoreCase)) might be better not to use LINQ string[] assetsInDirectory = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly) .Where(name => !name.ToLowerInvariant().EndsWith(".meta") && (!name.ToLowerInvariant().EndsWith(".unity")) && (!name.ToLowerInvariant().EndsWith("thumbs.db")) && (!name.ToLowerInvariant().EndsWith(".orig")) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "heureka" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "plugins" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "streamingassets" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor default resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().EndsWith(@".ds_store")) && (!name.ToLowerInvariant().EndsWith(@".workspace.mel")) && (!name.ToLowerInvariant().EndsWith(@".mayaswatches"))) .ToArray(); //TODO this could also be improved for performance for (int i = 0; i < assetsInDirectory.Length; i++) { assetsInDirectory[i] = assetsInDirectory[i].Substring(assetsInDirectory[i].IndexOf("/Assets") + 1); assetsInDirectory[i] = assetsInDirectory[i].Replace(@"\", "/"); } //Find any assets that does not live in UsedAssets List //TODO for performance reasons, perhaps dont to this for each folder, but just once, when finished? //That would mean to do folder creation and populating unused assets lists after all folders are traversed var result = assetsInDirectory.Where(p => !usedAssets.Any(p2 => UnityEditor.AssetDatabase.GUIDToAssetPath(p2.GUID) == p)); //Create new folder object ProjectFolderInfo afInfo = new ProjectFolderInfo(); //TODO this could also be improved for performance afInfo.DirectoryName = path.Substring(path.IndexOf("/Assets") + 1).Replace(@"\", "/"); afInfo.ParentIndex = parentIndex; if (heirarchyDepth == 0) afInfo.FoldOut = true; //Add to static list AssetHunterMainWindow.Instance.AddProjectFolderInfo(afInfo); if (parentIndex != -1) { AssetHunterMainWindow.Instance.GetFolderList()[parentIndex].AddChildFolder(afInfo); } UnityEngine.Object objToFind; foreach (string assetName in result) { bool bExclude = false; foreach (string excluder in AssetHunterMainWindow.Instance.settings.m_AssetSubstringExcludes) { //Exlude Asset Exclude substrings from settings //If we find an excluded asset just continue to next iteration in loop if (assetName.Contains(excluder, StringComparison.OrdinalIgnoreCase)) bExclude = true; } if (bExclude) continue; objToFind = AssetDatabase.LoadAssetAtPath(assetName, typeof(UnityEngine.Object)); if (objToFind == null) { Debug.LogWarning("Couldnt find " + assetName); continue; } SerializableSystemType assetType = new SerializableSystemType(objToFind.GetType()); if (assetType.SystemType != typeof(MonoScript) && (!AssetHunterMainWindow.Instance.settings.m_AssetTypeExcludes.Contains(assetType))) { AssetObjectInfo newAssetInfo = new AssetObjectInfo(assetName, assetType); afInfo.AddAsset(newAssetInfo); } objToFind = null; //Memory leak safeguard //This have heavy performance implications if(AssetHunterMainWindow.Instance.settings.m_MemoryCleanupActive) UnloadUnused(); } string[] nextLevelDirectories = System.IO.Directory.GetDirectories(path, "*.*", System.IO.SearchOption.TopDirectoryOnly); //Memory leak safeguard per folder if (!AssetHunterMainWindow.Instance.settings.m_MemoryCleanupActive) UnloadUnused(); foreach (string nld in nextLevelDirectories) { traverseDirectory(AssetHunterMainWindow.Instance.GetFolderList().IndexOf(afInfo), nld, usedAssets, (heirarchyDepth + 1), ref directoriesTraversed, validTypeList); } }
private static void traverseDirectory(int parentIndex, string path, List<BuildReportAsset> usedAssets, int heirarchyDepth, ref int directoriesTraversed, SortedDictionary<SerializableSystemType, bool> validTypeList) { directoriesTraversed++; EditorUtility.DisplayProgressBar( "Traversing Directories", "(" + directoriesTraversed + " of " + m_NumberOfDirectories + ") Analyzing " + path.Substring(path.IndexOf("/Assets") + 1), (float)directoriesTraversed / (float)m_NumberOfDirectories); //Get the settings to exclude vertain folders or suffixes foreach (UnityEngine.Object dir in AssetHunterMainWindow.Instance.settings.m_DirectoryExcludes) { //TODO Can this be done more elegantly int startingIndex = Application.dataPath.Length-6; string relativePath = path.Substring(startingIndex, path.Length - startingIndex); UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(relativePath, typeof(UnityEngine.Object)); if (dir == obj) { //This folder was exluded return; } } string[] assetsInDirectory = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly) .Where(name => !name.ToLowerInvariant().EndsWith(".meta") && (!name.ToLowerInvariant().EndsWith(".unity")) && (!name.ToLowerInvariant().EndsWith("thumbs.db")) && (!name.ToLowerInvariant().EndsWith(".orig")) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "heureka" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "plugins" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "streamingassets" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor default resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(@".ds_store")) && (!name.ToLowerInvariant().Contains(@".workspace.mel")) && (!name.ToLowerInvariant().Contains(@".mayaswatches"))) .ToArray(); for (int i = 0; i < assetsInDirectory.Length; i++) { assetsInDirectory[i] = assetsInDirectory[i].Substring(assetsInDirectory[i].IndexOf("/Assets") + 1); assetsInDirectory[i] = assetsInDirectory[i].Replace(@"\", "/"); } //Find any assets that does not live in UsedAssets List var result = assetsInDirectory.Where(p => !usedAssets.Any(p2 => UnityEditor.AssetDatabase.GUIDToAssetPath(p2.GUID) == p)); //Create new folder object ProjectFolderInfo afInfo = new ProjectFolderInfo(); afInfo.DirectoryName = path.Substring(path.IndexOf("/Assets") + 1).Replace(@"\", "/"); afInfo.ParentIndex = parentIndex; if (heirarchyDepth == 0) afInfo.FoldOut = true; //Add to static list AssetHunterMainWindow.Instance.AddProjectFolderInfo(afInfo); if (parentIndex != -1) { AssetHunterMainWindow.Instance.GetFolderList()[parentIndex].AddChildFolder(afInfo); } UnityEngine.Object objToFind; foreach (string assetName in result) { objToFind = AssetDatabase.LoadAssetAtPath(assetName, typeof(UnityEngine.Object)); if (objToFind == null) { Debug.LogWarning("Couldnt find " + assetName); continue; } SerializableSystemType assetType = new SerializableSystemType(objToFind.GetType()); if (assetType.SystemType != typeof(MonoScript) && (!AssetHunterMainWindow.Instance.settings.m_AssetTypeExcludes.Contains(assetType))) { AssetObjectInfo newAssetInfo = new AssetObjectInfo(assetName, assetType); afInfo.AddAsset(newAssetInfo); } objToFind = null; //Memory leak safeguard UnloadUnused(); } string[] nextLevelDirectories = System.IO.Directory.GetDirectories(path, "*.*", System.IO.SearchOption.TopDirectoryOnly); foreach (string nld in nextLevelDirectories) { traverseDirectory(AssetHunterMainWindow.Instance.GetFolderList().IndexOf(afInfo), nld, usedAssets, (heirarchyDepth + 1), ref directoriesTraversed, validTypeList); } }
private void showUnusedAssets() { EditorGUILayout.Separator(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Collapse All", GUILayout.Width(btnMinWidth))) { foreach (ProjectFolderInfo folder in m_ProjectFolderList) { folder.FoldOut = false; } } EditorGUILayout.Space(); if (GUILayout.Button("Expand All", GUILayout.Width(btnMinWidth))) { foreach (ProjectFolderInfo folder in m_ProjectFolderList) { folder.FoldOut = true; } } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); EditorGUILayout.Separator(); int indentLevel = 0; drawAssetFolderInfoRecursively(m_ProjectFolderList[0], indentLevel); if (m_assetMarkedForDeletion != null) { if (EditorUtility.DisplayDialog("Delete asset", "Are you sure you want to delete " + m_assetMarkedForDeletion.m_Name, "Yes", "No")) { m_assetMarkedForDeletion.Delete(m_unusedTypeDict); //Delete potential empty folders int deleteCount = 0; deleteEmptyDirectories(getSystemFolderPath(m_assetMarkedForDeletion.m_ParentPath), ref deleteCount); m_assetMarkedForDeletion = null; } else m_assetMarkedForDeletion = null; } else if (m_folderMarkedForDeletion != null) { int dialogChoice = EditorUtility.DisplayDialogComplex( "Clean all assets in folder", "You can delete all assets below this folder, or you can choose to make a backup first. That will create a unitypackage with all your deleted assets, but it will be slow", "Delete all", "Backup and delete (Slow!)", "Cancel"); switch (dialogChoice) { //Normal delete case 0: deleteAllInFolder(m_folderMarkedForDeletion, false); break; //Delete with backup case 1: deleteAllInFolder(m_folderMarkedForDeletion, true); break; //Cancel case 2: m_folderMarkedForDeletion = null; break; default: Debug.LogError("Unrecognized option."); break; } } }
private static void traverseDirectory(int parentIndex, string path, List <BuildReportAsset> usedAssets, int heirarchyDepth, ref int directoriesTraversed, SortedDictionary <SerializableSystemType, bool> validTypeList) { directoriesTraversed++; EditorUtility.DisplayProgressBar( "Traversing Directories", "(" + directoriesTraversed + " of " + m_NumberOfDirectories + ") Analyzing " + path.Substring(path.IndexOf("/Assets") + 1), (float)directoriesTraversed / (float)m_NumberOfDirectories); //Get the settings to exclude vertain folders or suffixes foreach (UnityEngine.Object dir in AssetHunterMainWindow.Instance.settings.m_DirectoryExcludes) { //TODO Can this be done more elegantly int startingIndex = Application.dataPath.Length - 6; string relativePath = path.Substring(startingIndex, path.Length - startingIndex); UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(relativePath, typeof(UnityEngine.Object)); if (dir == obj) { //This folder was exluded return; } } //Exclude types and folders that should not be reviewed //TODO perhaps improve performance of this step (Also use String.Contains(excluder, StringComparison.OrdinalIgnoreCase)) might be better not to use LINQ string[] assetsInDirectory = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly) .Where(name => !name.ToLowerInvariant().EndsWith(".meta") && (!name.ToLowerInvariant().EndsWith(".unity")) && (!name.ToLowerInvariant().EndsWith("thumbs.db")) && (!name.ToLowerInvariant().EndsWith(".orig")) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "heureka" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "plugins" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "streamingassets" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor default resources" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().Contains(Path.DirectorySeparatorChar + "editor" + Path.DirectorySeparatorChar)) && (!name.ToLowerInvariant().EndsWith(@".ds_store")) && (!name.ToLowerInvariant().EndsWith(@".workspace.mel")) && (!name.ToLowerInvariant().EndsWith(@".mayaswatches"))) .ToArray(); //TODO this could also be improved for performance for (int i = 0; i < assetsInDirectory.Length; i++) { assetsInDirectory[i] = assetsInDirectory[i].Substring(assetsInDirectory[i].IndexOf("/Assets") + 1); assetsInDirectory[i] = assetsInDirectory[i].Replace(@"\", "/"); } //Find any assets that does not live in UsedAssets List //TODO for performance reasons, perhaps dont to this for each folder, but just once, when finished? //That would mean to do folder creation and populating unused assets lists after all folders are traversed var result = assetsInDirectory.Where(p => !usedAssets.Any(p2 => UnityEditor.AssetDatabase.GUIDToAssetPath(p2.GUID) == p)); //Create new folder object ProjectFolderInfo afInfo = new ProjectFolderInfo(); //TODO this could also be improved for performance afInfo.DirectoryName = path.Substring(path.IndexOf("/Assets") + 1).Replace(@"\", "/"); afInfo.ParentIndex = parentIndex; if (heirarchyDepth == 0) { afInfo.FoldOut = true; } //Add to static list AssetHunterMainWindow.Instance.AddProjectFolderInfo(afInfo); if (parentIndex != -1) { AssetHunterMainWindow.Instance.GetFolderList()[parentIndex].AddChildFolder(afInfo); } UnityEngine.Object objToFind; foreach (string assetName in result) { bool bExclude = false; foreach (string excluder in AssetHunterMainWindow.Instance.settings.m_AssetSubstringExcludes) { //Exlude Asset Exclude substrings from settings //If we find an excluded asset just continue to next iteration in loop if (assetName.Contains(excluder, StringComparison.OrdinalIgnoreCase)) { bExclude = true; } } if (bExclude) { continue; } objToFind = AssetDatabase.LoadAssetAtPath(assetName, typeof(UnityEngine.Object)); if (objToFind == null) { Debug.LogWarning("Couldnt find " + assetName); continue; } SerializableSystemType assetType = new SerializableSystemType(objToFind.GetType()); if (assetType.SystemType != typeof(MonoScript) && (!AssetHunterMainWindow.Instance.settings.m_AssetTypeExcludes.Contains(assetType))) { AssetObjectInfo newAssetInfo = new AssetObjectInfo(assetName, assetType); afInfo.AddAsset(newAssetInfo); } objToFind = null; //Memory leak safeguard //This have heavy performance implications if (AssetHunterMainWindow.Instance.settings.m_MemoryCleanupActive) { UnloadUnused(); } } string[] nextLevelDirectories = System.IO.Directory.GetDirectories(path, "*.*", System.IO.SearchOption.TopDirectoryOnly); //Memory leak safeguard per folder if (!AssetHunterMainWindow.Instance.settings.m_MemoryCleanupActive) { UnloadUnused(); } foreach (string nld in nextLevelDirectories) { traverseDirectory(AssetHunterMainWindow.Instance.GetFolderList().IndexOf(afInfo), nld, usedAssets, (heirarchyDepth + 1), ref directoriesTraversed, validTypeList); } }