유니티 엔진 (Unity Engine)

Unity 에셋 참조를 Assets 폴더 하위에서 모두 찾는 방법

원생계 2023. 4. 11. 01:38

유니티 엔진으로 게임을 만들 때 종종 사용하는 메뉴 기능으로 Find References In Scene 이 있습니다. 특정 에셋을 우클릭하거나 Assets 메뉴 하위에서 이 메뉴를 찾아 클릭하면, 현재 씬에서 참조를 모두 찾아서 Hierarchy 에 보여주는 기능입니다.

그런데 가끔은, 현재 씬이 아니라, 모든 씬을 넘어 Assets 폴더 전체에서 참조를 찾고싶을 때가 있습니다. 불필요한 리소스나 스크립트를 정리해야 하거나, 수정해야할 때 다른 곳에서 참조가 걸려있는지를 확인하고 싶을 때인데요, 이런 기능을 추가해서 사용해봤습니다.

기능 이름은

"Find References In Assets Folder"

만들어봅시다.

먼저 스크립트를 하나 생성합니다.

(메뉴 이름과 클래스 이름이 동일할 필요는 없습니다. 이런류 기능들을 공통으로 관리하는 클래스가 있다면 그쪽으로 메소드만 추가해도 무관.)

그리고 아래처럼 스크립트 원형을 작성해줍니다.

 
public class FindReferencesInAssetsFolder : MonoBehaviour
{
    [MenuItem("Assets/Find References In Assets Folder", false, 25)]
    public static void Find()
    {
        // Do Something
    }
}

 

이렇게 스크립트를 구현한 뒤에 아무 에셋을 우클릭하면, 해당 메뉴 아이템이 추가된 것을 확인할 수 있습니다. 이제 내용을 채워 넣어봅시다.

스크립트는 아래 내용을 그대로 복붙하시면 됩니다.

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class FindReferencesInAssetsFolder : MonoBehaviour
{
    [MenuItem("Assets/Find References In Assets Folder", false, 25)]
    public static void Find()
    {
        var referenceCache = new Dictionary<string, List<string>>();

        string[] guids = AssetDatabase.FindAssets("", new[] { "Assets" });
        foreach (string guid in guids)
        {
            string assetPath = AssetDatabase.GUIDToAssetPath(guid);
            string[] dependencies = AssetDatabase.GetDependencies(assetPath, false);

            foreach (var dependency in dependencies)
            {
                if (referenceCache.ContainsKey(dependency))
                {
                    if (!referenceCache[dependency].Contains(assetPath))
                    {
                        referenceCache[dependency].Add(assetPath);
                    }
                }
                else
                {
                    referenceCache[dependency] = new List<string>() { assetPath };
                }
            }
        }

        string path = AssetDatabase.GetAssetPath(Selection.activeObject);
        Debug.Log("===== Find: " + path, Selection.activeObject);
        if (referenceCache.ContainsKey(path))
        {
            foreach (var reference in referenceCache[path])
            {
                Debug.Log(reference, AssetDatabase.LoadMainAssetAtPath(reference));
            }
        }
        else
        {
            Debug.LogWarning("No References");
        }
        referenceCache.Clear();
    }
}

이 기능의 동작은 상당히 단순(무식)한데,

먼저 Assets 폴더의 모든 에셋들의 guid 로 path 를 얻어낸 뒤에, 해당 에셋이 갖고 있는 의존(Dependency)를 모두 저장해둡니다. 여기서 의존관계에 있는 에셋 경로가 키(Key)값이 되도록 컨테이너를 생성하고, 중복된 의존을 가진 에셋 path 를 모두 List 로 저장해둡니다.

그리고 선택한 에셋의 path 를 Key 로 하여 탐색한 뒤에 저장된 List 를 모두 덤프하면, 이 리스트에 들어있는 에셋들에 모두 참조가 걸려있는 것이죠.

핵심은 AssetDatabase.GetDependencies() 함수로, 해당 에셋이 갖고있는 의존들을 모두 탐색해서 의존에셋 경로를 키값으로 수집하는 부분.

테스트로 Player.cs 스크립트의 참조를 모두 찾아달라고 실행해보면

이렇게 결과를 뱉어줍니다. GamePlay.unity 씬에서만 참조되고 있군요. 이렇게 특정 에셋이 어떤 에셋들에서 참조되고있는지 한 번에 찾을 수 있게 되었습니다. 단, 모든 에셋을 순회하기 때문에 에셋 개수가 많아질 수록 처리 속도는 느려질 수 있다는 점은 유의해야겠습니다.

728x90
반응형