How do I loop over all Assets folders and sub folders and get to a list all the prefabs in this folders?
Asked Answered
A

4

5

This code get all the sub folders in a Assets specific folder.

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;

public class AddComponents : Editor
{
    private static string GetClickedDirFullPath()
    {
        string clickedAssetGuid = Selection.assetGUIDs[0];
        string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
        string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);

        FileAttributes attr = File.GetAttributes(clickedPathFull);
        return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
    }

    private static string GetPath()
    {
        string path = GetClickedDirFullPath();
        int index = path.IndexOf("Assets");
        string result = path.Substring(index);

        return result;
    }

    private static string[] GetSubFoldersRecursive(string root)
    {
        var paths = new List<string>();

        // If there are no further subfolders then AssetDatabase.GetSubFolders returns 
        // an empty array => foreach will not be executed
        // This is the exit point for the recursion
        foreach (var path in AssetDatabase.GetSubFolders(root))
        {
            // add this subfolder itself
            paths.Add(path);

            // If this has no further subfolders then simply no new elements are added
            paths.AddRange(GetSubFoldersRecursive(path));
        }

        return paths.ToArray();
    }

    [MenuItem("Assets/Get Folders")]
    private static void GetFolders()
    {
        List<string> paths = new List<string>();
        string selectedPath = GetPath();
        var folders = GetSubFoldersRecursive(selectedPath);
        foreach (var path in folders)
        {
            paths.Add(path);
        }
    }
}

And this get all the prefabs from a specific folder but when I type the folder name :

public List<string> prefabsPaths;

    public void AddComponentsToObjects()
    {
        prefabsPaths = new List<string>();

        string[] assetsPaths = AssetDatabase.GetAllAssetPaths();

        foreach (string assetPath in assetsPaths)
        {
            if (assetPath.Contains("Archanor"))
            {
                if (assetPath.Contains("Prefabs"))
                {
                    prefabsPaths.Add(assetPath);
                }
            }
        }
    }

I want to combine both codes so when I make right click and select Get Path it will get all the prefabs from the selected path the right click on the path and the path all sub folders recursive.

Example :

Assets
  Folder1
  Folder2
    Folder3
     Folder4
     Folder5
  Folder6

If in the Assets I make mouse right click on the folder Folder2 and then select from the menu Get Path I want it to get all the prefabs from Folder2 and all the sub folders under Folder2. So In the end I will have a List of all the paths with the folders :

Folder2\1.prefab
Folder2\Folder3\2.prefab
Folder2\Folder3\3.prefab
Folder2\Folder4\4.prefab

In the end my goal is to be able to add to each prefab a component for example a Rigidbody. So if I have a folder with the 10 prefabs and under it 30 sub folders with more 200 prefabs then get all the folders and prefabs and add a component/s to all the prefabs in all folders.

Affairs answered 3/6, 2020 at 14:50 Comment(0)
A
1

This is what I wanted and working good for my case :

In the Assets right click on any Folder and then click on Add Components. It will loop all the folders and sub folders of the folder you did right click Add Components. Then it will find all the prefabs add to them a Rigidbody and save the changes.

Depending on how many prefabs you have it might be a bit slowly but it's doing the job.

Things to add :

Options to add more components or multiple components.

Creating a log/text file with all the changes made prefabs names what changes made and when.

Undo if there an option to make undo on Assets or to make the undo using the text file reading the changes made and revert back.

Backup : Once adding components to make a backup first in a temp folder of the original prefabs (could be also use for undo cases ).

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using UnityEditor;
using UnityEngine;

public class AddComponents : Editor
{
    private static string GetClickedDirFullPath()
    {
        string clickedAssetGuid = Selection.assetGUIDs[0];
        string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
        string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);

        FileAttributes attr = File.GetAttributes(clickedPathFull);
        return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
    }

    private static string GetPath()
    {
        string path = GetClickedDirFullPath();
        int index = path.IndexOf("Assets");
        string result = path.Substring(index);

        return result;
    }

    static List<string> paths = new List<string>();
    private static void GetFolders()
    {

        string selectedPath = GetPath();

        string[] assetsPaths = AssetDatabase.GetAllAssetPaths();

        foreach (string assetPath in assetsPaths)
        {
            if (assetPath.Contains(selectedPath))
            {
                if (assetPath.Contains("Prefabs"))
                {
                    paths.Add(assetPath);
                }
            }
        }
    }


    [MenuItem("Assets/Add Components")]
    public static void AddComponents()
    {
        GetFolders();

        for (int i = 0; i < paths.Count; i++)
        {
            if (File.Exists(paths[i]))
            {
                GameObject contentsRoot = PrefabUtility.LoadPrefabContents(paths[i]);

                // Modify Prefab contents.
                contentsRoot.AddComponent<Rigidbody>();

                // Save contents back to Prefab Asset and unload contents.
                PrefabUtility.SaveAsPrefabAsset(contentsRoot, paths[i]);
                PrefabUtility.UnloadPrefabContents(contentsRoot);
            }
        }
    }
}
Affairs answered 3/6, 2020 at 20:24 Comment(0)
S
2

Here is an alternative and simple way to do this.

string[] files = Directory.GetFiles("DirectoryPath", "*.prefab", SearchOption.AllDirectories);
Subtraction answered 3/6, 2020 at 15:1 Comment(1)
It's working to get the files but not the assets. How can I add to this a components ? I need to get the assets as prefabs not as files on the hard disk.Affairs
X
2

You can use "Resources.Load("[path]/[filename]") as [Class]" this will give you the asset, prefab, sprite etc you need. Important to note that this will only look in the folder "Resources" in the asset folder (the root in the unity project), so you have to create a "Resources" folder! This is also just a good idea because it can be very slow to look trough all files so this ensures it only looks at the important files. So you can use Vivek nuna's solution to get the file locations and Resources.Load to get the asset. For more information look here: https://docs.unity3d.com/ScriptReference/Resources.html

Hope this helps!

Xanthein answered 3/6, 2020 at 17:52 Comment(1)
Seems like someone else asked the same question here it is: #62166461Xanthein
L
1

To get actual prefab from path, use AssetDatabase.LoadAssetAtPath(path) and related methods.

It only works in editor, but I guess thats what you need

Ledge answered 3/6, 2020 at 18:30 Comment(0)
A
1

This is what I wanted and working good for my case :

In the Assets right click on any Folder and then click on Add Components. It will loop all the folders and sub folders of the folder you did right click Add Components. Then it will find all the prefabs add to them a Rigidbody and save the changes.

Depending on how many prefabs you have it might be a bit slowly but it's doing the job.

Things to add :

Options to add more components or multiple components.

Creating a log/text file with all the changes made prefabs names what changes made and when.

Undo if there an option to make undo on Assets or to make the undo using the text file reading the changes made and revert back.

Backup : Once adding components to make a backup first in a temp folder of the original prefabs (could be also use for undo cases ).

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using UnityEditor;
using UnityEngine;

public class AddComponents : Editor
{
    private static string GetClickedDirFullPath()
    {
        string clickedAssetGuid = Selection.assetGUIDs[0];
        string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
        string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);

        FileAttributes attr = File.GetAttributes(clickedPathFull);
        return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
    }

    private static string GetPath()
    {
        string path = GetClickedDirFullPath();
        int index = path.IndexOf("Assets");
        string result = path.Substring(index);

        return result;
    }

    static List<string> paths = new List<string>();
    private static void GetFolders()
    {

        string selectedPath = GetPath();

        string[] assetsPaths = AssetDatabase.GetAllAssetPaths();

        foreach (string assetPath in assetsPaths)
        {
            if (assetPath.Contains(selectedPath))
            {
                if (assetPath.Contains("Prefabs"))
                {
                    paths.Add(assetPath);
                }
            }
        }
    }


    [MenuItem("Assets/Add Components")]
    public static void AddComponents()
    {
        GetFolders();

        for (int i = 0; i < paths.Count; i++)
        {
            if (File.Exists(paths[i]))
            {
                GameObject contentsRoot = PrefabUtility.LoadPrefabContents(paths[i]);

                // Modify Prefab contents.
                contentsRoot.AddComponent<Rigidbody>();

                // Save contents back to Prefab Asset and unload contents.
                PrefabUtility.SaveAsPrefabAsset(contentsRoot, paths[i]);
                PrefabUtility.UnloadPrefabContents(contentsRoot);
            }
        }
    }
}
Affairs answered 3/6, 2020 at 20:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.