1. 삽질
…
아무 생각 없이 재귀로 폴더도 찾고, 메타 파일도 찾고, Regex로 guid도 찾고…
정신 차려보니 아래와 같은 소스 코드를 짜고 있었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/// <summary> 지정한 폴더 애셋의 절대 경로 찾기 </summary>
private string FindFolderAssetAbsPath(DefaultAsset folderAsset)
{
// Note: Assets 디렉토리로부터 하위 폴더 전부 순회하며 폴더 이름 일치하는 경로 탐색
DirectoryInfo rootDirectory = Directory.CreateDirectory(Application.dataPath);
string found = null;
bool guidFound = AssetDatabase.TryGetGUIDAndLocalFileIdentifier(folderAsset, out string guid, out long _);
if (guidFound == false) return null;
Local_FindDirectoryAbsPath(rootDirectory, folderAsset.name, guid);
return found;
// 내부 재귀 메소드
void Local_FindDirectoryAbsPath(DirectoryInfo currentDirectory, string folderName, string folderGuid)
{
if (found != null) return;
// 일치하는 경로명 찾은 경우 Meta 파일의 GUID 일치 여부 확인
if (currentDirectory.Name == folderName)
{
FileInfo metaFile = new FileInfo(currentDirectory.FullName + ".meta");
string metaGUID = GetGuidFromMetaFile(metaFile);
// GUID까지 일치
if (metaGUID == folderGuid)
{
found = currentDirectory.FullName;
return;
}
}
// 하위 폴더들 재귀 탐색
DirectoryInfo[] subFolders = currentDirectory.GetDirectories();
foreach (var folder in subFolders)
{
Local_FindDirectoryAbsPath(folder, folderName, folderGuid);
}
}
}
private string GetGuidFromMetaFile(FileInfo metaFileInfo)
{
if (metaFileInfo == null || metaFileInfo.Exists == false) return null;
string contents = File.ReadAllText(metaFileInfo.FullName);
Debug.Log(contents);
Match match = Regex.Match(contents, @"guid: (.+)[\r\n]");
if (match.Groups.Count > 1)
{
return match.Groups[1].Value;
}
return null;
}
Usage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// EditorWindow 상속 클래스 내부
public DefaultAsset folderAsset;
private GUIContent folderLabel;
private void OnGUI()
{
if(folderLabel == null)
folderLabel = new GUIContent("Folder");
folderAsset = EditorGUILayout.ObjectField(folderLabel, folderAsset, typeof(DefaultAsset), false) as DefaultAsset;
if (GUILayout.Button("Find"))
{
if (folderAsset != null)
{
string path = FindFolderAssetAbsPath(folderAsset);
Debug.Log(path);
}
}
}
이정도 기능은 있지 않을까.. 하고 찾아보니
역시나 AssetDatabase
클래스가 모두 갖고 있는 기능이었다.
교훈 : 친절하게 구현된 API를 먼저 찾자.
2. Unity API 사용
- NOTE :
DefaultAsset
클래스는UnityEngine.Object
의 자식으로, 폴더 애셋을 가리킨다.
…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// EditorWindow 상속 클래스 내부
public DefaultAsset folderAsset;
private GUIContent folderLabel;
private void OnGUI()
{
if(folderLabel == null)
folderLabel = new GUIContent("Folder");
folderAsset = EditorGUILayout.ObjectField(folderLabel, folderAsset, typeof(DefaultAsset), false) as DefaultAsset;
if (GUILayout.Button("Call") && folderAsset != null)
{
// 폴더 애셋 -> GUID 찾기
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(folderAsset, out string guid, out long _);
if (guid != null)
{
// GUID -> Assets/ 로 시작하는 상대 경로 찾기
string path = AssetDatabase.GUIDToAssetPath(guid);
path = path.Substring(path.IndexOf('/') + 1);
// 드라이브 경로로부터 시작하는 절대 경로 조립
string fullPath = Path.Combine(Application.dataPath, path);
Debug.Log(fullPath);
}
}
}
3. 사용하기 편리한 확장 메소드
- 반드시
UNITY_EDITOR
조건 내에서 사용해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static class UnityEditorAssetExtensions
{
/// <summary> 폴더 애셋으로부터 Assets로 시작하는 로컬 경로 얻기 </summary>
public static string GetLocalPath(this UnityEditor.DefaultAsset @this)
{
bool success =
UnityEditor.AssetDatabase.TryGetGUIDAndLocalFileIdentifier(@this, out string guid, out long _);
if (success)
return UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
else
return null;
}
/// <summary> 폴더 애셋으로부터 절대 경로 얻기 </summary>
public static string GetAbsolutePath(this UnityEditor.DefaultAsset @this)
{
string path = GetLocalPath(@this);
if (path == null)
return null;
path = path.Substring(path.IndexOf('/') + 1);
return Application.dataPath + "/" + path;
}
/// <summary> 폴더 애셋으로부터 DirectoryInfo 객체 얻기 </summary>
public static System.IO.DirectoryInfo GetDirectoryInfo(this DefaultAsset @this)
{
string absPath = GetAbsolutePath(@this);
return (absPath != null) ? new System.IO.DirectoryInfo(absPath) : null;
}
}