DEV Community

Cover image for [Unity] Publish assets that automatically organizes folders.
uni928
uni928

Posted on • Updated on

[Unity] Publish assets that automatically organizes folders.

I created an asset that automatically organizes folders in Unity.
I would like to release it to you in the hope that it will be useful to you.

Please download ver1.1.4 (latest version) from the following site.
https://drive.google.com/file/d/1EuwCiYTttfgwJ6yMBZW2p-GcQmuzC728/view?usp=sharing


This asset automatically organizes Unity folders.

After importing this asset,
place the files and folders you want to sort into a specific folder, and run it from the menu bar at the top of Unity.
The rest will be sorted automatically.

If you are not confident in organizing folders or are looking at projects created by others,
using this may make management and viewing easier.

After sorting with this function,
as development progresses,
folders will likely become messy.
Therefore, we recommend re-sorting periodically.

Since this function only checks the dependencies of scene files to see if they are in use,
it will not determine that they are in use if there are no dependencies, such as when they are loaded with Resources.
Therefore, the determination of when they are in use may be quite lenient.
Thank you for your understanding.


Folder rules

The folder structure is as follows:

"Prefabs"
"Scripts"
"Animations"
"Materials"
"PhysicsMaterials"
"Fonts"
"Textures"
"Audio"
"Models"
"Shaders"
"Resources"
"Editor"
"Plugins"
"Other"

Create folders and create folders for
"2 or more scenes with dependencies"
"1 scene with dependencies"
"0 scenes with dependencies"
(Of course, the folder names are short English.)

The reason for creating a Project folder is that when assets are introduced, they are placed directly under Asset, making it easier to distinguish between assets and non-assets.

In the "1 scene with dependencies folder", folders with scene names are created and stored.
Image description


I've left the code here so you can check the contents.

Since there are a lot of files from version 1.1.1 onwards,
this will be an introduction to version 1.1.0.

I apologize for the length of the code.

The hierarchy of the sorting folders must be strictly adhered to, so if you are installing it, I recommend installing it from unitypackage.

using System.Collections.Generic;
using UnityEngine;

namespace SephirothTools
{
    [UnityEditor.InitializeOnLoad]
    public class SephirothOrganizeFolders
    {
        public const bool isAutoSave = false;

        [UnityEditor.MenuItem("Tools/ExecSephirothOrganizeFolders")]
        private static void ExecSephirothOrganizeFolders()
        {
            System.DateTime nowDateTime = System.DateTime.Now;

            TakeBackUP(nowDateTime);

            List<string> subDirectoryList = GetSubDirectories("Assets/SephirothOrganizeFolders/OrganizeFolders");
            subDirectoryList.Add(AssetsToAbsolutePath("Assets/SephirothOrganizeFolders/OrganizeFolders"));

            List<string> sceneFilePathList = new();

            foreach (string oneDirectorie in subDirectoryList)
            {
                foreach (string oneFile in System.IO.Directory.GetFiles(AssetsToAbsolutePath(oneDirectorie)))
                {
                    if (oneFile.EndsWith(".unity") && System.IO.File.Exists(oneFile))
                    {
                        sceneFilePathList.Add(oneFile.Replace('\\', '/'));
                    }
                }
            }

            CreateDirectories(sceneFilePathList);

            foreach (string oneDirectorie in subDirectoryList)
            {
                foreach (string oneFile in System.IO.Directory.GetFiles(AssetsToAbsolutePath(oneDirectorie)))
                {
                    string changeOneFile = oneFile.Replace('\\', '/');
                    if (changeOneFile.Contains("SephirothOrganizeFolders/OrganizeFolders/HowToSephirothOrganizeFolders"))
                    {
                        continue;
                    }
                    if(System.IO.Path.GetFileName(changeOneFile).StartsWith("."))
                    {
                        continue;
                    }
                    if (changeOneFile.EndsWith(".meta"))
                    {
                        continue;
                    }
                    if(changeOneFile.EndsWith(".unity"))
                    {
                        continue;
                    }

                    string upFolderName = changeOneFile.Substring(0, changeOneFile.LastIndexOf("/"));
                    upFolderName = upFolderName.Substring(upFolderName.LastIndexOf("/") + 1);

                    string guid = null;
                    foreach(string oneLine in System.IO.File.ReadAllText(AssetsToAbsolutePath(changeOneFile + ".meta")).Split('\n'))
                    {
                        if(oneLine.StartsWith("guid"))
                        {
                            guid = oneLine.Substring(6);
                            break;
                        }
                    }

                    List<string> findSceneNameList = new();
                    if (guid != null)
                    {
                        foreach (string oneScene in sceneFilePathList)
                        {
                            string readText = System.IO.File.ReadAllText(AssetsToAbsolutePath(oneScene));
                            if (readText.Contains(guid))
                            {
                                findSceneNameList.Add(oneScene);
                            }
                        }
                    }

                    string genreName = null;
                    if (changeOneFile.Contains("/Resources/"))
                    {
                        genreName = "Resources";
                    }
                    else if (changeOneFile.Contains("/Editor/"))
                    {
                        genreName = "Editor";
                    }
                    else if (changeOneFile.Contains("/Plugins/"))
                    {
                        genreName = "Plugins";
                    }
                    else if (changeOneFile.EndsWith(".cs") || changeOneFile.EndsWith(".js"))
                    {
                        genreName = "Scripts";
                    }
                    else if (changeOneFile.EndsWith(".prefab"))
                    {
                        genreName = "Prefabs";
                    }
                    else if (changeOneFile.EndsWith(".anim") || changeOneFile.EndsWith(".controller"))
                    {
                        genreName = "Animations";
                    }
                    else if (changeOneFile.EndsWith(".mat") || changeOneFile.EndsWith(".material"))
                    {
                        genreName = "Materials";
                    }
                    else if (changeOneFile.EndsWith(".physicmaterial"))
                    {
                        genreName = "PhysicsMaterials";
                    }
                    else if (changeOneFile.EndsWith(".ttf") || changeOneFile.EndsWith(".otf") || changeOneFile.EndsWith(".dfont"))
                    {
                           genreName = "Fonts";
                    }
                    else if (changeOneFile.EndsWith(".fbx") || changeOneFile.EndsWith(".dae") || changeOneFile.EndsWith(".dxf") || changeOneFile.EndsWith(".obj") || changeOneFile.EndsWith(".max") || changeOneFile.EndsWith(".blend"))
                    {
                        genreName = "Models";
                    }
                    else if (changeOneFile.EndsWith(".shader"))
                    {
                        genreName = "Shaders";
                    }
                    else if (changeOneFile.EndsWith(".png") || changeOneFile.EndsWith(".bmp") || changeOneFile.EndsWith(".exr") || changeOneFile.EndsWith(".gif") || changeOneFile.EndsWith(".hdr") || changeOneFile.EndsWith("iff") || changeOneFile.EndsWith(".jpeg") || changeOneFile.EndsWith(".jpg") || changeOneFile.EndsWith(".pict") || changeOneFile.EndsWith(".psd") || changeOneFile.EndsWith(".tga") || changeOneFile.EndsWith(".tiff") || changeOneFile.EndsWith(".tif"))
                    {
                        genreName = "Textures";
                    }
                    else if (changeOneFile.EndsWith(".mp3") || changeOneFile.EndsWith(".ogg") || changeOneFile.EndsWith(".wav") || changeOneFile.EndsWith(".aiff") || changeOneFile.EndsWith(".aif") || changeOneFile.EndsWith(".mod") || changeOneFile.EndsWith(".it") || changeOneFile.EndsWith(".s3m") || changeOneFile.EndsWith(".xm"))
                    {
                        genreName = "Audio";
                    }
                    else
                    {
                        genreName = "Other";
                    }

                    if (findSceneNameList.Count == 0)
                    {
                        string targetFile1 = AssetsToAbsolutePath("Assets/Projects/" + genreName + "/NoUse" + genreName + "/" + upFolderName + "/" + changeOneFile.Substring(changeOneFile.LastIndexOf("/") + 1) + ".meta");
                        string targetFile2 = AssetsToAbsolutePath("Assets/Projects/" + genreName + "/NoUse" + genreName + "/" + upFolderName + "/" + changeOneFile.Substring(changeOneFile.LastIndexOf("/") + 1));
                        {
                            string[] folderSplit = targetFile1.Split("/");
                            string nowFolder = folderSplit[0];
                            for(int i = 1; i < folderSplit.Length - 1; i++)
                            {
                                nowFolder += "/" + folderSplit[i];
                                if(!System.IO.Directory.Exists(nowFolder))
                                {
                                    System.IO.Directory.CreateDirectory(nowFolder);
                                }
                            }
                        }

                        if (System.IO.File.Exists(targetFile1))
                        {
                            System.IO.File.Delete(targetFile1);
                        }
                        System.IO.File.Move(AssetsToAbsolutePath((changeOneFile + ".meta")), targetFile1);

                        if (System.IO.File.Exists(targetFile2))
                        {
                            System.IO.File.Delete(targetFile2);
                        }
                        System.IO.File.Move(AssetsToAbsolutePath(changeOneFile), targetFile2);
                    }
                    else if(1 < findSceneNameList.Count)
                    {
                        string targetFile1 = AssetsToAbsolutePath("Assets/Projects/" + genreName + "/Common" + genreName + "/" + upFolderName + "/" + changeOneFile.Substring(changeOneFile.LastIndexOf("/") + 1) + ".meta");
                        string targetFile2 = AssetsToAbsolutePath("Assets/Projects/" + genreName + "/Common" + genreName + "/" + upFolderName + "/" + changeOneFile.Substring(changeOneFile.LastIndexOf("/") + 1));
                        {
                            string[] folderSplit = targetFile1.Split("/");
                            string nowFolder = folderSplit[0];
                            for (int i = 1; i < folderSplit.Length - 1; i++)
                            {
                                nowFolder += "/" + folderSplit[i];
                                if (!System.IO.Directory.Exists(nowFolder))
                                {
                                    System.IO.Directory.CreateDirectory(nowFolder);
                                }
                            }
                        }

                        if (System.IO.File.Exists(targetFile1))
                        {
                            System.IO.File.Delete(targetFile1);
                        }
                        System.IO.File.Move(AssetsToAbsolutePath((changeOneFile + ".meta")), targetFile1);

                        if (System.IO.File.Exists(targetFile2))
                        {
                            System.IO.File.Delete(targetFile2);
                        }
                        System.IO.File.Move(AssetsToAbsolutePath(changeOneFile), targetFile2);
                    }
                    else
                    {

                        string sceneName = findSceneNameList[0].Substring(findSceneNameList[0].LastIndexOf("/") + 1);
                        sceneName = sceneName.Substring(0, sceneName.Length - 6);

                        string targetFile1 = AssetsToAbsolutePath("Assets/Projects/" + genreName + "/Scene" + genreName + "/" + sceneName + "/" + upFolderName + "/" + changeOneFile.Substring(changeOneFile.LastIndexOf("/") + 1) + ".meta");
                        string targetFile2 = AssetsToAbsolutePath("Assets/Projects/" + genreName + "/Scene" + genreName + "/" + sceneName + "/" + upFolderName + "/" + changeOneFile.Substring(changeOneFile.LastIndexOf("/") + 1));
                        {
                            string[] folderSplit = targetFile1.Split("/");
                            string nowFolder = folderSplit[0];
                            for (int i = 1; i < folderSplit.Length - 1; i++)
                            {
                                nowFolder += "/" + folderSplit[i];
                                if (!System.IO.Directory.Exists(nowFolder))
                                {
                                    System.IO.Directory.CreateDirectory(nowFolder);
                                }
                            }
                        }

                        if (System.IO.File.Exists(targetFile1))
                        {
                            System.IO.File.Delete(targetFile1);
                        }
                        System.IO.File.Move(AssetsToAbsolutePath((changeOneFile + ".meta")), targetFile1);


                        if (System.IO.File.Exists(targetFile2))
                        {
                            System.IO.File.Delete(targetFile2);
                        }
                        System.IO.File.Move(AssetsToAbsolutePath(changeOneFile), targetFile2);
                    }
                }
            }
            foreach(string oneScene in sceneFilePathList)
            {
                string resultFileName = AssetsToAbsolutePath("Assets/Projects/Scenes/" + oneScene.Substring(oneScene.LastIndexOf("/") + 1));
                if(oneScene.Equals(resultFileName))
                {
                    continue;
                }
                if (System.IO.File.Exists(resultFileName))
                {
                    System.IO.File.Delete(resultFileName);
                }
                System.IO.File.Move(oneScene, resultFileName);
            }
            foreach(string oneDirectory in System.IO.Directory.GetDirectories(AssetsToAbsolutePath("Assets/SephirothOrganizeFolders/OrganizeFolders")))
            {
                UnityEditor.FileUtil.DeleteFileOrDirectory(AssetsToAbsolutePath(oneDirectory));
                System.IO.File.Delete(AssetsToAbsolutePath(oneDirectory + ".meta"));
            }

            UnityEditor.AssetDatabase.Refresh();

            if (!isAutoSave)
            {
#pragma warning disable CS0162 // Unreachable code detected
                System.IO.File.Delete("Assets/SephirothOrganizeFolders/OrganizeFolders/." + nowDateTime.ToString("yyyy_MM_dd_HH_mm_ss") + ".unitypackage");
#pragma warning restore CS0162 // Unreachable code detected
            }

            UnityEditor.AssetDatabase.Refresh();
            Debug.Log("Move Finished...");
        }

        private static void CreateDirectories(List<string> sceneFilePathList)
        {
            List<string> genreNameList = new();
            genreNameList.Add("Scripts");
            genreNameList.Add("Prefabs");
            genreNameList.Add("Animations");
            genreNameList.Add("Materials");
            genreNameList.Add("PhysicsMaterials");
            genreNameList.Add("Fonts");
            genreNameList.Add("Textures");
            genreNameList.Add("Audio");
            genreNameList.Add("Models");
            genreNameList.Add("Shaders");
            genreNameList.Add("Resources");
            genreNameList.Add("Editor");
            genreNameList.Add("Plugins");
            genreNameList.Add("Other");

            List<string> createList = new();
            createList.Add("Assets/Projects");
            createList.Add("Assets/Projects/Scenes");

            foreach (string oneGenreName in genreNameList)
            {
                createList.Add("Assets/Projects/" + oneGenreName);
                createList.Add("Assets/Projects/" + oneGenreName + "/Common" + oneGenreName);
                createList.Add("Assets/Projects/" + oneGenreName + "/NoUse" + oneGenreName);
                createList.Add("Assets/Projects/" + oneGenreName + "/Scene" + oneGenreName);
            }

            for(int i = 0; i < createList.Count; i++)
            {
                if(!System.IO.Directory.Exists(AssetsToAbsolutePath(createList[i])))
                {
                    System.IO.Directory.CreateDirectory(AssetsToAbsolutePath(createList[i]));
                }
            }
        }

        private static List<string> GetSubDirectories(string path)
        {
            string[] directoriesArr = System.IO.Directory.GetDirectories(AssetsToAbsolutePath(path));
            List<string> result = new List<string>(directoriesArr);
            foreach (string innerPath in directoriesArr)
            {
                result.AddRange(GetSubDirectories(innerPath));
            }
            return result;
        }

        private static string AssetsToAbsolutePath(string self)
        {
            if (self.StartsWith("Assets"))
            {
                self = Application.dataPath + self.Substring(6);
            }
            return self;
        }

        private static void TakeBackUP(System.DateTime nowDateTime)
        {
            if (!System.IO.Directory.Exists(AssetsToAbsolutePath("Assets/SephirothOrganizeFolders/OrganizeFolders"))) System.IO.Directory.CreateDirectory(AssetsToAbsolutePath("Assets/SephirothOrganizeFolders/OrganizeFolders"));
            UnityEditor.AssetDatabase.ExportPackage("Assets", AssetsToAbsolutePath("Assets/SephirothOrganizeFolders/OrganizeFolders/." + nowDateTime.ToString("yyyy_MM_dd_HH_mm_ss") + ".unitypackage"), UnityEditor.ExportPackageOptions.Recurse);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Above, we have released the folder organization assets.

We hope that this will be helpful for your development.
Thank you for viewing.

Top comments (0)