* UObject 시스템
- 속성 초기화 자동화
UObject는 초기화 시 자동으로 0으로 초기화 된다. 이후 클래스 생성자에서 사용자가 멤버를 초기화할 수 있다.
- AActor, UActorComponent의 참조 업데이트 자동화
AActor와 UActorComponent가 파괴되는 경우 리플렉션 시스템이 이 객체를 관리하고 있다면 이 객체에 대한 모든 참조는 자동으로 널로 초기화된다. 여기서 리플렉션 시스템의 관리를 받기 위해서는 UProperty 나 TArray와 같은 언리얼 엔진에서 제공하는 컨테이너를 사용해야한다.
이는 이러한 다른 코드에 의해 삭제될 때 언제든 널로 초기화되기 때문에 허상 포인터(dangling pointer)는 따로 신경쓰지 않고 널 체크만 잘하면 안정적으로 사용할 수 있다. 널 체크를 통해 일반적인 널 포인터와 삭제된 객체 두 가지 케이스를 판별할 수 있다.
이 때문에 대부분 UObject들은 엔진의 관리를 받아 자동 널 초기화와 가비지컬렉션을 방지하기 위해 UProperty나 TArray와 같은 언리얼 엔진 제공 컨테이너를 사용해야한다. 만약 가비지컬렉션을 방지하지 않고(삭제에 관여하지 않고, 소유하지 않고) 널만 체크하고 싶다면 TWeakObjectPtr을 사용해야한다. TWeakObjectPtr은 객체 접근 전 유효성 검증을 요청하여 삭제된 객체라면 널로 설정된다.
에디터에서 에셋을 Force Delete하는 경우에는 모든 UProperty는 널로 설정된다. 따라서 에셋 UObejct의 경우 널 체크 후 사용하도록 코드를 작성해야 한다.
- 직렬화
UObject를 직렬화 시 transient로 지정되지 않고, 생성자 이후 기본 값에서 변경되었다면 해당 UProperty 값들은 자동으로 읽고 쓰게 된다. 예를 들어 레벨에서 한 인스턴스의 값이 A로 설정되었다면 값 A가 저장되고 리로드된다.
UProperty가 추가되거나 삭제되었을 때 기존 로딩된 컨텐츠는 원활하게 처리되며 새로운 속성은 새 CDO에서 복사된 기본 값을 가져오고, 삭제된 속성은 무시된다.
UObject::Serialize를 재정의 함으로써 커스텀 직렬화 로직을 만들 수 있다. 주로 데이터 검증, 추가 업데이트 로직 등을 위해 사용된다.
- 속성 값 업데이트
UClass의 CDO가 변경되었을 때(생성자에서 속성 값이 변경되었을 때) 일반적으로 로드된 해당 클래스의 모든 인스턴스에 변경사항을 적용한다.
예외가 존재한다. 인스턴스 중에 이전 CDO의 해당 변수의 값과 동일하지 않다면, 새로운 CDO의 해당 변수의 값으로 초기화되지 않는다. 예를 들어 HP값이 CDO에서 100인 인스턴스가 CDO에서 200으로 변경된다면 일반적인 경우라면 모두 200으로 업데이트 된다. 하지만 100이 아닌 다른 값으로 변경한 인스턴스(HP를 500 등)은 200으로 업데이트 되지 않는다.
- 에디터 통합
에디터에서도 UProperty를 인지할 수 있기 때문에 여러 옵션을 통해 에디터에 노출시킬 수 있다.
- 란타임 타입 정보와 캐스팅
UObject 들은 리플렉션 시스템의 일부이기 때문에 UClass에 대한 정보를 가지고 있다.
정보를 기반으로 다음과 같은 기능을 제공한다.
- Super : 부모 클래스의 이름을 typedef로 정의하고 있다. 이 키워드를 통해 부모 클래스에 접근하면 된다.
- IsA : 해당 클래스가 입력으로 들어온 클래스의 자식 클래스인지 확인한다. (부모클래스와 자식클래스의 계층을 표현하는 배열과 해당 클래스의 인덱스를 통해 판별한다.)
- Cast : 부모 클래스에서 안전하게 자식 클래스로 캐스팅할 수 있다. 만약 자식 클래스 객체가 아니면 널 포인터를 반환한다.
- 가비지 컬렉션
언리얼 엔진은 UObject에 대해 가비지컬렉션 기능을 제공하고 있으며, 가비지 컬렉션은 더 이상 참조되지 않거나 명시적으로 표시(PendingKill)된 객체들을 일정 간격으로 확인하여 삭제한다.
@ 참조 그래프(Reference Graph)
언리얼 엔진은 참조 그래프를 만들어 관리함으로써 어떤 UObject가 사용 여부를 판단할 수 있다. 참조 그래프의 루트에는 루트 셋(root set)으로 지정된 UObject들이 존재한다. 어떤 UObject라도 루트 셋에 추가될 수 있으며 가비지 컬렉션 수행 시 루트 셋부터 탐색을 시작하게 된다. 참조 트리에서 찾을 수 없는 참조 되지 않는 UObject들은 불필요한 것으로 간주되어 삭제된다.
@ UProperty와 언리얼 엔진 컨테이너(TArray 등)
일반적으로 생명을 유지하고 싶은 UObject들은 UProperty나 언리얼 엔진 컨테이너를 사용해야 한다. 단 AActor와 UActorComponent 종류의 클래스는 종종 예외다.
@ AActor와 UActorComponent 종류의 특별한 경우
Actor는 일반적으로 루트 셋에 연결된 객체(Actor가 속한 레벨 등)에 의해 참조된다. ActorComponent 역시 Actor에 의해 참조된다.
레벨과 같은 객체는 게임이 종료되거나 스트리밍 중인 레벨이 언로드되거나 레벨이 전이되지 않는 한 계속 유지되기 때문에 그냥 놔두면 원할 때 삭제할 수 없다. 이를 위해 게임 진행중에 Actor를 명시적으로 삭제할 수 있는 방법을 제공하고 있다. 이 방법은 Destroy 함수이며 Actor에 PendingKill이라는 플래그를 켜주는 역할을 한다. PendingKill로 마킹된 Actor는 다음 가비지 컬렉션 사이클 때 할당 해제된다. ActorComponent도 비슷하게 DestroyComponent라는 함수를 제공한다. 하지만 일반적으로 이를 소유중인 Actor가 파괴될 때 같이 파괴된다.
Actor가 명시적으로 Destroy를 호출 했을 때 바로 삭제되지 않고 PendingKill만 켜지게 된다. 그러면 이를 참조하는 다른 곳에서 해당 Actor가 삭졔 예정임에도 사용할 가능성이 높다. 이를 방지하기 위해 Actor 포인터에 대해 널 포인터(Actor 포인터가 UProperty 종류로 되어있어야 할당 해제될 때 널 포인터로 초기화된다.)와 PendingKill을 동시에 검사하는 IsValid라는 함수를 사용하여 체크하고 사용하도록 해야한다.
https://forums.unrealengine.com/t/garbage-collection-doesnt-null-my-pointer/469022
Garbage collection doesn't null my pointer
Are you checking right after destroying or when the GC has actually kicked in?
forums.unrealengine.com
https://create-new-worlds.tistory.com/145
[UnrealEngine] Actor 생명주기(Actor Lifecycle)
* 정의 Actor가 로드되거나 스폰되고, 소멸할 때까지의 과정을 Actor 생명주기(Actor Lifecycle)라고 한다. * 동작 방식 세부 내용은 여기서 확인하면 된다. https://docs.unrealengine.com/4.27/en-US/Programmin..
create-new-worlds.tistory.com
- 네트워크 리플리케이션
UObject 시스템은 네트워크 통신관련 강력한 기능들도 포함하고 있다.
UProperty의 속성 지정자를 통해 리플리케이션하도록 지정할 수 있다. 일반적으로 서버에서 변수가 변경되면 이 변경된 내용을 감지하여 모든 클라이언트에게 안정적으로 보낸다. 클라이언트는 리플리케이션을 통해 변수가 변경될 때 선택적으로 콜백 함수를 지정할 수 있다.
UFunction은 속성 지정자를 통해 원격 머신에서 수행되도록 할 수 있다.
- server 함수는 클라이언트 머신에서 호출되며 서버 머신에서 서버 버전 Actor의 함수가 호출되도록 한다.
- client 함수는 서버 머신에서 호출되며 해당 Actor의 소유 클라이언트 머신에서 클라이언트 버전 Actor의 함수를 호출한다.
'게임 엔진 > Unreal Engine' 카테고리의 다른 글
[UnrealEngine] Dynamic Delegate, Multicast Delegate (0) | 2022.04.03 |
---|---|
[UnrealEngine] Delegate (0) | 2022.03.30 |
[UnrealEngine] UObject (0) | 2022.03.30 |
[UnrealEngine] 속성 지정자(Property Specifiers) (0) | 2022.03.29 |
[UnrealEngine] 리플렉션(Unreal Property System (Reflection)) (0) | 2022.03.29 |