Unity 검색

A metallic abstract cube on a black background
A metallic abstract cube on a black background
다루는 주제
공유

최신 LTS 릴리스에서 다형 직렬화(polymorphic serialization)는 개선된 사용자 협업과 API 액세스를 제공하며 누락된 유형의 더 세분화된 처리를 지원합니다.

SerializeReference 속성을 사용하면 필드에 할당된 오브젝트를 값으로 직렬화하지 않고 레퍼런스로 직렬화할 수 있습니다. 참조되는 오브젝트를 '관리되는 레퍼런스'라고 합니다. SerializeReference 속성이 있는 필드는 다형성 및 null 값을 지원하는 역할을 합니다. 최근에 Unity 2021 LTS는 관리되는 레퍼런스를 위한 Stable ID를 추가했으며, 이는 누락된 유형에 대한 세분화된 처리와 개선된 API 액세스를 제공합니다. 이 블로그에서는 변경 사항을 자세히 소개하고 이러한 변경 사항이 어떤 도움이 되는지 살펴봅니다.

Stable ID

관리되는 레퍼런스는 호스트의 직렬화 데이터 내에 저장되며, 여기서 호스트는 MonoBehaviour 또는 ScriptableObject에서 파생된 클래스 등의 Unity 오브젝트입니다. 이렇게 하기 위해, 관리되는 레퍼런스 오브젝트마다 고유한 ID가 할당됩니다.

SerializeReference 속성이 있는 필드는 참조된 오브젝트의 ID를 저장하여 직렬화됩니다. 관리되는 레퍼런스는 ManagedReferenceRegistry라는 목록에 저장되며, 이 목록은 호스트의 직렬화된 데이터에 포함됩니다.

Unity 2019 및 2020 LTS에서 ID는 콘텐츠의 뎁스 우선 순회를 통해 저장 시에 할당되었습니다. 이 접근 방식의 주요 단점은 배열 요소의 순서를 재지정하는 등의 사소한 작업으로 인해 영향을 받는 파일이 크게 달라질 수 있다는 점입니다. 파일 내에서 큰 변경 사항은 병합 충돌로 이어질 수 있으며, 병합 충돌은 협업 환경에서 작업할 때 해결하기 어렵습니다.

그래서 Unity는 Stable ID를 도입했습니다. Stable ID를 사용하면 오브젝트에 고유한 ID를 할당했을 때, 연속적인 저장 및 로드 사이클 동안 같은 ID를 유지할 수 있습니다. 다시 말해 호스트에서 관리되는 레퍼런스의 필드 할당을 변경하고 다시 저장해도 ID가 변경되지 않습니다.

Stable ID의 이점을 설명하기 위해 다음과 같은 예시를 들어 보겠습니다.

Serialize source code

이 예시에서는 관리되는 레퍼런스 오브젝트 배열을 생성하는데, Sandwich 클래스와 Fruit 클래스의 인스턴스가 번갈아 채워집니다. LunchBox1.asset 파일을 검사하여 배열 콘텐츠를 확인할 수 있습니다.

Sample Inspector

첫 번째 항목을 목록 끝으로 옮기면 기본 에셋 파일이 변경됩니다. 다음 diff 툴 스크린샷을 보면 2021.3에서 배열의 오브젝트에 배열 순서와 무관한 ID가 있을 때 diff가 얼마나 간단해지는지 알 수 있습니다.

2020.3:

2020.3 array ordering in Unity

2021.3:

2021.3 array ordering in Unity

원활한 협업을 위한 고유 ID

Stable ID 기능은 Unity 파일 내의 변경 사항을 줄이는 것뿐만 아니라 일반적인 협업 과정에서 발생하는 문제를 해결하도록 만들어졌습니다. 이전 버전에서는 같은 호스트에서 두 명의 사용자가 관리되는 레퍼런스 오브젝트를 추가하면 같은 ID가 할당되어 병합하기가 어려웠습니다. 특히 여러 필드에서 하나의 관리되는 레퍼런스 오브젝트를 참조할 수 있기 때문에 더욱 어려웠습니다. Unity 2021부터 ID는 시간 및 시스템 정보 해시를 기반으로 생성되기 때문에 사실상 충돌이 일어나지 않도록 할 수 있습니다. 더 고급 시나리오에서는 SerializationUtility.SetManagedReferenceIdForObject를 호출하여 기본 ID 할당 시스템을 오버라이드할 수도 있습니다.

누락된 유형 처리

SerializeReference는 다형성을 지원하므로 필드 유형에서 파생된 클래스 인스턴스에 필드를 할당할 수 있습니다. 실제로 유니티는 모든 C# 클래스의 루트 기본 클래스인 “System.Object”를 필드 유형으로 지원합니다. 하지만 성공적으로 컴파일된 프로젝트에서 이전에 사용할 수 있었고 씬이나 에셋 파일에 저장된 클래스의 정의가 누락될 수 있습니다. 경우에 따라 소스 파일을 제거하거나 클래스 이름을 변경하거나 클래스를 다른 어셈블리로 옮겼을 때 클래스가 누락되기도 합니다.

SerializedReference 호스트 오브젝트를 로드할 때 각 관리되는 레퍼런스 오브젝트의 정규화된 유형 이름을 검사하며, 이를 인스턴스화하려면 유효한 클래스 유형으로 다시 변경해야 합니다. 이전 Unity 버전에서 누락된 클래스는 유효한 상태의 관리되는 레퍼런스 오브젝트를 로드하지 않고 전체 '호스트' 오브젝트를 오류 상태로 만들었습니다. 예를 들어 15개의 관리되는 레퍼런스 오브젝트로 구성된 배열이 포함된 '호스트'가 있지만 하나의 오브젝트를 변경할 수 없는 경우, 모든 오브젝트가 인스펙터에 표시되지 않았습니다. 호스트 오브젝트를 검사할 때 오브젝트가 오류 상태로 표시되지 않더라도 콘솔에 오류가 기록되고 모든 편집 내용이 자동으로 삭제됩니다.

Unity 2021에서는 이제 로드할 수 있는 모든 관리되는 레퍼런스 오브젝트를 인스턴스화하여 누락된 오브젝트를 null로 바꿉니다. 사용자는 이를 통해 호스트 오브젝트의 상태를 더 자세하게 확인할 수 있고 누락된 유형을 쉽게 해결할 수 있습니다. 한편 호스트 오브젝트가 로드되는 동안 누락된 유형이 복구되는 경우, 트리거된 도메인 리로드가 관리되는 레퍼런스 오브젝트를 복구하고 이를 참조하는 모든 필드가 올바르게 업데이트됩니다.

다음은 누락된 유형이 있는 오브젝트가 인스펙터에 어떻게 나타나는지 보여 주는 예시입니다.

2020.3에서는 Fruit 클래스가 누락되었지만, 인스펙터에는 어떤 배열 요소도 표시되지 않고 오류가 표시되지도 않습니다.

2021.3에서는 인스펙터에 누락된 Fruit 오브젝트가 null 항목으로 표시된다는 경고가 뜨고, Sandwich 오브젝트는 계속 표시됩니다.

누락된 유형과 관련된 콘솔의 오류 메시지도 업데이트되어 반복이 줄어들었으며, 어떤 호스트 오브젝트에 누락된 유형이 있는지만 식별합니다.

다음은 2020.3의 오류 메시지입니다.

이와 비교하여 2021.3의 오류 메시지는 다음과 같습니다.

프리팹

ID 개선 사항을 활용하면 프리팹의 관리되는 레퍼런스 오브젝트에 대한 변경 사항도 이제 관리되는 레퍼런스 오브젝트에 유지됩니다. 이전에는 PropertyModification이 필드를 대상으로 할 때 필드로 이어지는 첫 번째 프로퍼티 경로를 기반으로 했습니다. 다시 말해 배열의 순서를 재지정하는 등의 이유로 경로가 바뀌면 PropertyModification이 의도했던 관리되는 레퍼런스를 추적하지 못하고 문제가 제대로 해결되지 않습니다. Unity 2021부터 PropertyModification은 Stable ID(managedReferences[12345].myString)를 통합하는 경로를 사용하여 관리되는 레퍼런스 오브젝트를 참조합니다. 이를 통해 호스트에서 오브젝트를 옮겨도 관리되는 레퍼런스 오브젝트가 오버라이드된 값을 유지할 수 있습니다.

API 지원 개선

SerializeReference와 관련된 기능을 선보이기 위해 Unity API에 새로운 클래스인 SerializationUtility를 추가했습니다. 예를 들어 누락된 유형에 대한 복구 계획이 없는 경우 호스트에서 경고 상태를 제거하는 등 SerializationUtility.ClearAllManagedReferencesWithMissingTypes()를 사용하여 누락된 유형에 대한 레퍼런스를 제거할 수 있습니다.

SerializedProperty.managedReferenceValue에 대한 읽기 권한 옵션을 비롯해 CustomEditor의 컨텍스트에서 관리되는 레퍼런스를 사용할 수 있는 API를 개선했습니다.

새로운 메서드에 대한 레퍼런스에는 샘플 코드도 포함되어 있으며, Unity는 직렬화와 관련된 레퍼런스 주제에 대한 자세한 내용을 통합했습니다.

직렬화 코드는 기존의 관리되는 레퍼런스 형식과 호환되므로 SerializeReference를 사용하는 기존 프로젝트는 새 Unity 버전에서 매끄럽게 로드될 것입니다. 보통 SerializeReference를 사용할 때 Stable ID 개념이나 새 API 메서드에 대한 깊은 지식이 필요하지는 않습니다. 하지만 내부적인 것이더라도 이러한 개선 사항은 일반적으로 사용할 때 유용하며, 특히 협업 환경에서 매우 유용합니다.

이 블로그를 통해 유용한 기능을 더 자세히 알아볼 수 있었기를 바랍니다. 직렬화 팀은 모든 Unity 사용자를 위해 계속 기능을 개선하고 있으며, 전용 포럼 스레드에서 여러분의 피드백과 토론을 기다리고 있습니다.

다루는 주제