Last active
September 22, 2023 18:33
-
-
Save mob-sakai/b98a62c1f2c94c1fef9021101635a5cd to your computer and use it in GitHub Desktop.
Automatically remove empty folders in project for Unity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEditor; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Linq; | |
using System; | |
/// <summary> | |
/// Remove empty folders automatically. | |
/// </summary> | |
public class RemoveEmptyFolders : UnityEditor.AssetModificationProcessor | |
{ | |
public const string kMenuText = "Assets/Remove Empty Folders"; | |
static readonly StringBuilder s_Log = new StringBuilder(); | |
static readonly List<DirectoryInfo> s_Results = new List<DirectoryInfo>(); | |
/// <summary> | |
/// Raises the initialize on load method event. | |
/// </summary> | |
[InitializeOnLoadMethod] | |
static void OnInitializeOnLoadMethod() | |
{ | |
EditorApplication.delayCall += () => Valid(); | |
} | |
/// <summary> | |
/// Raises the will save assets event. | |
/// </summary> | |
static string[] OnWillSaveAssets(string[] paths) | |
{ | |
// If menu is unchecked, do nothing. | |
if (!EditorPrefs.GetBool(kMenuText, false)) | |
return paths; | |
// Get empty directories in Assets directory | |
s_Results.Clear(); | |
var assetsDir = Application.dataPath + Path.DirectorySeparatorChar; | |
GetEmptyDirectories(new DirectoryInfo(assetsDir), s_Results); | |
// When empty directories has detected, remove the directory. | |
if (0 < s_Results.Count) | |
{ | |
s_Log.Length = 0; | |
s_Log.AppendFormat("Remove {0} empty directories as following:\n", s_Results.Count); | |
foreach (var d in s_Results) | |
{ | |
s_Log.AppendFormat("- {0}\n", d.FullName.Replace(assetsDir, "")); | |
FileUtil.DeleteFileOrDirectory(d.FullName); | |
} | |
// UNITY BUG: Debug.Log can not set about more than 15000 characters. | |
s_Log.Length = Mathf.Min(s_Log.Length, 15000); | |
Debug.Log(s_Log.ToString()); | |
s_Log.Length = 0; | |
AssetDatabase.Refresh(); | |
} | |
return paths; | |
} | |
/// <summary> | |
/// Toggles the menu. | |
/// </summary> | |
[MenuItem(kMenuText)] | |
static void OnClickMenu() | |
{ | |
// Check/Uncheck menu. | |
bool isChecked = !Menu.GetChecked(kMenuText); | |
Menu.SetChecked(kMenuText, isChecked); | |
// Save to EditorPrefs. | |
EditorPrefs.SetBool(kMenuText, isChecked); | |
OnWillSaveAssets(null); | |
} | |
[MenuItem(kMenuText, true)] | |
static bool Valid() | |
{ | |
// Check/Uncheck menu from EditorPrefs. | |
Menu.SetChecked(kMenuText, EditorPrefs.GetBool(kMenuText, false)); | |
return true; | |
} | |
/// <summary> | |
/// Get empty directories. | |
/// </summary> | |
static bool GetEmptyDirectories(DirectoryInfo dir, List<DirectoryInfo> results) | |
{ | |
bool isEmpty = true; | |
try | |
{ | |
isEmpty = dir.GetDirectories().Count(x => !GetEmptyDirectories(x, results)) == 0 // Are sub directories empty? | |
&& dir.GetFiles("*.*").All(x => x.Extension == ".meta"); // No file exist? | |
} | |
catch | |
{ | |
} | |
// Store empty directory to results. | |
if (isEmpty) | |
results.Add(dir); | |
return isEmpty; | |
} | |
} |
Solution 2020.2: Lines 48:
FileUtil.DeleteFileOrDirectory(d.FullName); FileUtil.DeleteFileOrDirectory(d.Parent + "\\" + d.Name + ".meta"); // unity 2020.2 need to delete the meta too
This worked for me. I wrote it this way
foreach (var d in s_Results)
{
// Line 1: s_Log.AppendFormat("- {0}\n", d.FullName.Replace(assetsDir, ""));
FileUtil.DeleteFileOrDirectory(d.FullName);
FileUtil.DeleteFileOrDirectory(d.Parent + "\\" + d.Name + ".meta"); // unity 2020.2 need to delete the meta too
}
I wonder if // Line 1: s_Log.AppendFormat("- {0}\n", d.FullName.Replace(assetsDir, ""));
is required
It is achievable without using IO. This is a context version, select folders to clean up, right click > Delete Empty Folders.
You can adapt it for project wide if you dare.
namespace Framework.Editor.Extensions
{
using UnityEngine;
using UnityEditor;
internal static class DeleteEmptyFolders
{
[MenuItem("Assets/Delete Empty Folders")]
static void deleteEmptyFolders()
{
foreach (var item in Selection.objects)
{
TryDeleteEmptyFolders(item);
}
}
private static void TryDeleteEmptyFolders(UnityEngine.Object obj)
{
if (!AssetDatabase.IsMainAsset(obj))
return;
// checks if the asset is a folder
if (obj.GetType() != typeof(UnityEditor.DefaultAsset))
return;
string dir = AssetDatabase.GetAssetPath(obj);
var subdirs = AssetDatabase.GetSubFolders(dir);
string[] strBuffer = new string[1];
foreach (var sub in subdirs)
{
strBuffer[0] = sub;
var assets = AssetDatabase.FindAssets("*", strBuffer);
if(assets.Length == 0)
{
Debug.Log("Deleteing : " + sub);
AssetDatabase.MoveAssetToTrash(sub);
}
}
}
}
}
Need to change line 97
.All(x => x.Extension == ".meta" || x.Name.Contains("DS_Store")); // No important files?
In Mac there are hidden files called .DS_Store.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Solution 2020.2: Lines 48: