[Unity, Editor] SOManagementWindow 제작 일기 Part.3

2025. 5. 15. 23:49·Editor
목차
  1. AssemblyLoadSystem
  2. SOManagementWindow 변경 부분

저번에 만들었던 기능에서 SO에 직접 넣어서 Type을 찾는 것이 불편해서 Assembly를 활용하여 Load하는 방식을 채택하였다.

Assembly는 내부적으로 Dictionary로 구현되어 있어 Load가 굉장히 빠른 편이다. 때문에 Assembly를 선택하였다.

그리고 이렇게 하면 ScriptableObject를 상속받는 Script가 생길 때마다. 자동으로 업로드를 해준다.

 

변경된 코드는 거의 없고 추가된 Script가 있다.

 

AssemblyLoadSystem

전체 코드

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace LJS.Editing.SOManagement
{
    [Serializable]
    public struct AssemblyInfo
    {
        public string assemblyName;
        public List<string> typeNameList;
    }
    
    [Serializable]
    [CreateAssetMenu(fileName = "AssemblyLoadSystem", menuName = "LJS/SO/AssemblyLoadSystem")]
    public class AssemblyLoadSystem : ScriptableObject
    {
        public List<Type> GetLoadTypeList { get; } = new();
        [SerializeField] private List<AssemblyInfo> GetAssemblyInfoList;
        
        private Stopwatch sw = new Stopwatch();

        public List<Type> ReturnLoadTypeList(bool sorting = false)
        {
            if (sorting)
                return GetLoadTypeList.OrderBy(x => x.Name).ToList();
            
            return GetLoadTypeList;
        }
        
        public void RefreshType()
        {
            sw.Start();
            LoadAssembly();
            GetLoadTypeList.Clear();
            foreach (var info in GetAssemblyInfoList)
            {
                Assembly assemblyInfo = Assembly.Load(info.assemblyName);
                foreach (var typeName in info.typeNameList)
                {
                    GetLoadTypeList.Add(assemblyInfo.GetType(typeName));
                }

            }
            foreach (var type in GetLoadTypeList)
            {
                Debug.Log($"RefreshType : {type}");
            }
            sw.Stop();
            
            Debug.Log($"Late Time : {(float)sw.ElapsedMilliseconds / 1000}S");
        }
        
        public void LoadAssembly()
        {
            List<AssemblyInfo> newAssemblyInfoList = new();
            var listOfBs = (
                from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
                from type in domainAssembly.GetTypes()
                where typeof(ScriptableObject).IsAssignableFrom(type)
                      && !typeof(EditorWindow).IsAssignableFrom(type)
                      && !typeof(Editor).IsAssignableFrom(type)
                select type).ToArray();
            if (GetLoadTypeList.Count != listOfBs.Length)
            {
                foreach (var item in listOfBs)
                {
                    string typeName = item.ToString();
                    if (typeName.StartsWith("UnityEngine.") == false
                     && typeName.StartsWith("UnityEditor.") == false
                     && typeName.StartsWith("Unity.") == false
                     && typeName.StartsWith("UnityEditorInternal.") == false
                     && typeName.StartsWith("TreeEditor.") == false
                     && typeName.StartsWith("SpriteShapeObjectPlacementEditor") == false
                     && typeName.StartsWith("AddressableAssets.") == false
                     && typeName.StartsWith("DownloadableSample") == false
                     && typeName.StartsWith("LightPlacementTool") == false
                     && typeName.StartsWith("FullScreenPassRendererFeatureEditor") == false
                     && typeName.StartsWith("FullScreenPassRendererFeature") == false
                     && typeName.StartsWith("Packages.") == false
                     && typeName.StartsWith("TMPro.") == false
                     && typeName.StartsWith("Timeline") == false
                     && typeName.StartsWith("TestRunner.") == false
                     && typeName.StartsWith("System.") == false
                     && typeName.StartsWith("LJS.Editing.SOManagement.") == false
                     && typeName.StartsWith("JetBrains.") == false)
                    {
                       AssemblyInfo newInfo = new AssemblyInfo();
                       newInfo.assemblyName = item.Assembly.GetName().Name;
                       newInfo.typeNameList = new();
                       newInfo.typeNameList.Add(typeName);
                       if (newAssemblyInfoList.Exists(x
                               => x.assemblyName == newInfo.assemblyName))
                       {
                           newAssemblyInfoList.Find(x => x.assemblyName == newInfo.assemblyName)
                               .typeNameList.Add(typeName);
                       }
                       else
                       {
                           newAssemblyInfoList.Add(newInfo);
                       }
                    }
                }
                if (newAssemblyInfoList.Count == GetAssemblyInfoList.Count)
                {
                    for (int i = 0; i < GetAssemblyInfoList.Count; ++i)
                    {
                        AssemblyInfo assemblyInfo = GetAssemblyInfoList[i];
                        var newAssemblyInfo = newAssemblyInfoList.
                            Find(x => x.assemblyName 
                                      == assemblyInfo.assemblyName);
                        if (newAssemblyInfo.typeNameList.Count
                            == assemblyInfo.typeNameList.Count)
                        {
                            // Debug.Log("AssemblyInfoList Count is Same");
                            if (!newAssemblyInfo.typeNameList.
                                Equals(assemblyInfo.typeNameList))
                            {
                                // Debug.Log("Find different Point");
                                foreach (var item in newAssemblyInfo.typeNameList)
                                {
                                    // Debug.Log(item);
                                    if (!assemblyInfo.typeNameList.Contains(item))
                                    {
                                        assemblyInfo.typeNameList.Add(item);
                                    }
                                }
                            }
                        }
                        else
                        {
                            // Debug.Log("AssemblyInfoList Count is Not Same");
                            assemblyInfo.typeNameList
                                = newAssemblyInfo.typeNameList;
                        }

                        GetAssemblyInfoList[i] = assemblyInfo;
                    }
                }
                else
                {
                    GetAssemblyInfoList = newAssemblyInfoList;
                }
            }
        }

        public void ResetAll()
        {
            GetAssemblyInfoList.Clear();
        }
    }
}

기능을 간단하게 요약하면 ScriptableObject를 상속받는 Class를 전부 가지고 온 뒤 원하는 Type만 들고 오는 방식이다.

ScriptableObject로 구현한 이유는 데이터 저장 용도이다.

 

근데 이게 그냥 불러오고 분류하고 저장하면 끝이 아니다. 이 상태로 가져온 Type.Getype를 사용하여 Type을 Load 하게 되면 AssemblyDefinition 때문에 Type를 가져올 수 없다. 왜냐하면 이게 Type이 Assembly에 묶여서 있는 구조 때문에 그냥 Load 하려고 하면 안되고 Assembly에서 GetType을 해야한다.

그래서 Assembly를 Load 한 다음에 그 Assembly에서 GetType를 하면 불러와진다.

여튼 이렇게 하면 Type를 가져올 수 있다.

대충 중요한 부분만 훑어보자.

var listOfBs = (
    from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
    from type in domainAssembly.GetTypes()
    where typeof(ScriptableObject).IsAssignableFrom(type)
          && !typeof(EditorWindow).IsAssignableFrom(type)
          && !typeof(Editor).IsAssignableFrom(type)
    select type).ToArray();

MainDomain에서 현재 Assembly를  들고 오고 ScriptableObject를 상속받되, EditorWindow와 Editor를 상속 받지 않는 Type들을 전부 들고 온다.

 

if (typeName.StartsWith("UnityEngine.") == false
 && typeName.StartsWith("UnityEditor.") == false
 && typeName.StartsWith("Unity.") == false
 && typeName.StartsWith("UnityEditorInternal.") == false
 && typeName.StartsWith("TreeEditor.") == false
 && typeName.StartsWith("SpriteShapeObjectPlacementEditor") == false
 && typeName.StartsWith("AddressableAssets.") == false
 && typeName.StartsWith("DownloadableSample") == false
 && typeName.StartsWith("LightPlacementTool") == false
 && typeName.StartsWith("FullScreenPassRendererFeatureEditor") == false
 && typeName.StartsWith("FullScreenPassRendererFeature") == false
 && typeName.StartsWith("Packages.") == false
 && typeName.StartsWith("TMPro.") == false
 && typeName.StartsWith("Timeline") == false
 && typeName.StartsWith("TestRunner.") == false
 && typeName.StartsWith("System.") == false
 && typeName.StartsWith("LJS.Editing.SOManagement.") == false
 && typeName.StartsWith("JetBrains.") == false)

이건 필요 없는 Type들을 분류 해주는 조건문이다.

 

SOManagementWindow 변경 부분

[SerializeField] private AssemblyLoadSystem _assemblyLoadSystemSO;

변수 추가했고

_assemblyLoadSystemSO.RefreshType();
foreach (var type in _assemblyLoadSystemSO.ReturnLoadTypeList(true))

그냥 로드만 해주고 Refresh 해주었다.

 

여튼 이렇게 하면

아래가 Window Open 시간이고

위가 Assembly Load 시간이다. 굉장히 빠른 걸 알 수가 있다.

 

다음장에서 바뀐 생성 시스템을 다루겠다.

'Editor' 카테고리의 다른 글

[Unity,Editor] SOManagementWindow 제작 일기 Part.4  (0) 2025.05.20
[Unity, Editor] SOManagementWindow 제작 일기 Part.2  (0) 2025.04.25
[Unity, Editor] SOManagementWindow 제작 일기 Part.1  (0) 2025.04.25
[졸업 작품, Unity]Item EditorWindow로 관리하기  (0) 2025.03.18
[Editor] 적 생성 Editor Window 코드 부분 제작  (0) 2024.10.10
  1. AssemblyLoadSystem
  2. SOManagementWindow 변경 부분
'Editor' 카테고리의 다른 글
  • [Unity,Editor] SOManagementWindow 제작 일기 Part.4
  • [Unity, Editor] SOManagementWindow 제작 일기 Part.2
  • [Unity, Editor] SOManagementWindow 제작 일기 Part.1
  • [졸업 작품, Unity]Item EditorWindow로 관리하기
HK1206
HK1206
고3 게임 개발자의 개발 일지
  • HK1206
    GGM-LJS
    HK1206
  • 전체
    오늘
    어제
    • 분류 전체보기 (25)
      • Unity (16)
      • Shader (1)
      • Editor (8)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
HK1206
[Unity, Editor] SOManagementWindow 제작 일기 Part.3

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.