본문 바로가기
유니티

유니티 자동화 툴 만들기<프로젝트 에셋 관련 기능 정리>

by JunHDev 2025. 11. 1.

서론


- 현재 기존 작업 유지보수, 사이드 프로젝트, 신규 프로젝트 준비를 동시에 진행하고 있다.

AI가 발전하면서 개발 속도는 빨라지고 있지만, 반복되는 작업에 들어가는 시간은 여전히 같다. 이 시간을 단축할 수 있다면 좋지 않을까? 싶고 또한 협업에도 도움이 될 것 같아 해당 툴을 제작하게 되었다.

제작하면서 새롭게 알게 된 기능들을 정리하고 기억하기 위해 글을 작성한다.

 

 

UnityEditor. AssetDatabase


- 에디터 안에서 프로젝트의 에셋(프리팹, 스크립트, 텍스처, 사운드 등)을 검색·생성·이동·삭제·가져오기(Import)·메타데이터 관리 등을 할 수 있게 해주는 에디터 전용(런타임 불가) 클래스다.

 

기능

 

  • 검색
    • FindAssets(filter) : 타입/라벨/이름 필터로 GUID 목록 검색
    • GetDependencies(path, recursive) : 에셋이 참조하는 의존성 목록 조회
  • 로드
    • LoadAssetAtPath<T>(path) : 경로로 에셋 객체 로드
    • LoadAllAssetsAtPath(path) : 서브에셋 포함 로드
  • 생성/추가
    • CreateAsset(obj, path) : 새 에셋 파일 생성
    • AddObjectToAsset(obj, path) : 기존 에셋에 서브오브젝트로 추가
    • CreateFolder(parent, newFolderName) : 폴더 생성
  • 이동/복제/삭제/이름 변경
    • MoveAsset(oldPath, newPath)
    • DuplicateAsset(path, newPath)
    • DeleteAsset(path)
    • RenameAsset(path, newName)
  • 메타/경로/식별자
    • GUIDToAssetPath(guid), AssetPathToGUID(path)
    • TryGetGUIDAndLocalFileIdentifier(obj, out guid, out localId)
    • GetAssetPath(obj) / IsMainAsset(obj) / GetMainAssetTypeAtPath(path)
  • 가져오기/리프레시/저장
    • ImportAsset(path, ImportAssetOptions)
    • Refresh() : 디스크 변경 사항 스캔
    • SaveAssets() : 메타/프로젝트 저장
    • 대량 작업 최적화: StartAssetEditing() / StopAssetEditing()
  • 라벨 관리
    • GetLabels(obj) / SetLabels(obj, labels)
  • 검증
    • IsValidFolder(path), Contains(obj)

에디터에서만 사용해야 하므로 전처리기를 통해 분기 처리한다.

 

AddressableAssetGroup


Addressables 시스템에서 에셋을 묶어 **빌드/배포 단위(AssetBundle 묶음 + 카탈로그 메타)**로 관리하는 컨테이너이다.

 

- 각 그룹은 스키마(Schema) 설정을 통해 빌드/로딩 경로, 압축, 해시, 캐싱, 콘텐츠 업데이트 전략 등을 제어합니다.

- 그룹 안에는 여러 **엔트리(Entry)**가 있으며, 각 엔트리는 특정 에셋(프리팹/사운드/텍스처 등)과 그 주소(Address), 라벨(Label) 정보를 가진다.

 

해당 클래스를 통해 그룹을 새로 만들거나 확장하는 메소드를 예시로 작성했다.

  /// <summary>
  /// Addressables.CreateGroup의 다양한 오버로드를 탐색하고 가장 적합한 것을 호출한다.
  /// 지원 대상(우선순위 순서):
  /// 1) CreateGroup(string, bool, bool, bool, params Type[] types)
  /// 2) CreateGroup(string, bool, bool, bool, IEnumerable&lt;AddressableAssetGroupSchema&gt; schemasToCopy, Type[] types)
  /// 3) CreateGroup(string, bool, bool, bool, List&lt;AddressableAssetGroupSchema&gt; schemasToCopy)
  /// </summary>
  private static AddressableAssetGroup CreateGroupCompat(AddressableAssetSettings settings, string groupName, Type[] schemaTypes)
  {
      var t = typeof(AddressableAssetSettings);
      var methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Public);
      MethodInfo best = null;

      // 1) params Type[] 단독
      best = methods.FirstOrDefault(m =>
      {
          if (m.Name != "CreateGroup")
          {
              return false;
          }

          var ps = m.GetParameters();
          if (ps.Length != 5)
          {
              return false;
          }

          return ps[0].ParameterType == typeof(string)
                 && ps[1].ParameterType == typeof(bool)
                 && ps[2].ParameterType == typeof(bool)
                 && ps[3].ParameterType == typeof(bool)
                 && ps[4].ParameterType.IsArray
                 && ps[4].ParameterType.GetElementType() == typeof(Type);
      });

      if (best != null)
      {
          object[] args =
          {
              groupName,
              false,
              false,
              false,
              schemaTypes
          };
          return (AddressableAssetGroup)best.Invoke(settings, args);
      }

      // 2) IEnumerable<AddressableAssetGroupSchema>, Type[]
      best = methods.FirstOrDefault(m =>
      {
          if (m.Name != "CreateGroup")
          {
              return false;
          }

          var ps = m.GetParameters();
          if (ps.Length != 6)
          {
              return false;
          }

          bool fifthOk = typeof(System.Collections.Generic.IEnumerable<AddressableAssetGroupSchema>).IsAssignableFrom(ps[4].ParameterType);
          bool sixthOk = ps[5].ParameterType.IsArray && ps[5].ParameterType.GetElementType() == typeof(Type);
          return ps[0].ParameterType == typeof(string)
                 && ps[1].ParameterType == typeof(bool)
                 && ps[2].ParameterType == typeof(bool)
                 && ps[3].ParameterType == typeof(bool)
                 && fifthOk
                 && sixthOk;
      });

      if (best != null)
      {
          object[] args =
          {
              groupName,
              false,
              false,
              false,
              null,         // schemasToCopyFrom 없음
              schemaTypes   // 붙일 스키마 타입들
          };
          return (AddressableAssetGroup)best.Invoke(settings, args);
      }

      // 3) List<AddressableAssetGroupSchema> 단독
      best = methods.FirstOrDefault(m =>
      {
          if (m.Name != "CreateGroup")
          {
              return false;
          }

          var ps = m.GetParameters();
          if (ps.Length != 5)
          {
              return false;
          }

          bool fifthOk = typeof(List<AddressableAssetGroupSchema>).IsAssignableFrom(ps[4].ParameterType);
          return ps[0].ParameterType == typeof(string)
                 && ps[1].ParameterType == typeof(bool)
                 && ps[2].ParameterType == typeof(bool)
                 && ps[3].ParameterType == typeof(bool)
                 && fifthOk;
      });

      if (best != null)
      {
          object[] args =
          {
              groupName,
              false,
              false,
              false,
              new List<AddressableAssetGroupSchema>() // 빈 목록 전달
          };
          var group = (AddressableAssetGroup)best.Invoke(settings, args);

          // 스키마는 수동으로 Add
          if (group != null)
          {
              EnsureDefaultSchemas(group);
          }

          return group;
      }

      // 찾지 못함
      return null;
  }

 

 

SystemIO


- 새로 글 작성 예정.

 

 

큰 타이틀로 나누면 이 정도로 정리할 수 있을 것 같다.

아래는 새로 만든 툴을 사용한 영상이다.

 

 

사운드가 포함돼 있습니다.

 

 

'유니티' 카테고리의 다른 글

오디오 믹서 (Aduio Mixer)  (1) 2025.09.14
Custom Editor  (0) 2025.08.30
스크립팅 백엔드  (2) 2025.03.30
RectTransformUtility  (3) 2025.03.19
RectTransformUntility에 대해서  (17) 2025.01.07