UnrealEngine/언리얼

[UE5] 언리얼 프로퍼티 시스템 ?

H프레임 2023. 1. 30. 22:54

UPROPERTY(), UCLASS() ,USTRUCT() ,UENUM() ,UFUNCTION()

 

언리얼 C++ 작업을 하면서 많이 봤던 UCLASS, UPROPERTY. 사실 UPROPERTY를 사용해서 지정자를 넣어주면 블루프린트에서 사용할 수 있다. 라고만 생각해왔던 때가 있었다. 처음 언리얼을 접했을 때 튜토리얼 따라하기, 구글링으로 찾아서 방법 따라하기 등을 많이 했었기에 그냥 그런가보다 하고 생각했다. 

 

하지만 이제는 제대로 알고 써야할 때가 온 것 같아 조금씩 찾아보며 공부하고 있다.

 

언리얼 프로퍼티 시스템, 언리얼 리플렉션, 리플렉션 시스템 등으로 많은 정보를 찾을 수 있었다. 언리얼에서 말하는 프로퍼티 시스템이 뭘까?

 

공식 문서를 찾아서 봤을 때, 사실 번역이 이상한건지 말이 어려운건지 10퍼센트도 못알아 들었다. 

 

그래서 그냥 설명하는 대로 클래스를 검색해보거나 키워드를 코드에서 검색해 보기도 했다. 

 

 

https://www.unrealengine.com/ko/blog/unreal-property-system-reflection

 

언리얼 문서에서 설명하는 내용이 궁금하면 위의 링크를 이용하면 된다.

 

 

리플렉션? 프로퍼티 시스템?

 

리플렉션과 프로퍼티 시스템은 사실 하나를 가리키는 키워드이다. 언리얼에서 프로퍼티 시스템이라고 쓰는 이유까지도 위의 링크에 잘 나와있다.

 

리플렉션은 가비지 콜렉션, 블루프린트 에디터 연동 등에 사용된다.

 

우선, 구글링하면 나오는 내용과 공식 문서에 적힌 내용들을 나열해보겠다.

 

Java나 C#에는 리플렉션이라는 시스템이 존재한다고 한다. 하지만 C++ 에서는 존재하지 않아서 언리얼에서 만들어서 제공하고 있다고 설명하고 있다. 

 

언리얼에서 설명하는 리플렉션이란 프로그램이 실행되는 중에 자기 자신( UCLASS , UENUM ,USTRUCT , UFUNCTION ...)을 조사할 수 있다는 것이다.

 

언리얼에는 헤더 툴 UHT(Unreal Header Tool) 이라는 것이 있는데 이 헤더툴이 컴파일 하기전에 헤더를 쭉 읽어서 메타 데이터로 만든 뒤에 UClass에 클래스의 계층 구조 / 멤버 변수 / 함수를 저장한다.  이걸 리플렉션(프로퍼티 시스템)이라고 부른다.

 

이렇게만 보면 어디서 본적 있는 내용들일 것이다.  저것만 보고는 이해가 안가서 실제로 뜯어봤다.

 

먼저 UMG_Tab이라는 클래스를 만들면  #include에 generated.h 라는 path가 보일 것이다. 그리고 동시에 UCLASS()도 볼 수 있다. 클래스를 만들면 항상 볼 수 있는 곳에 표시를 해두었다.

 

 

여기서 generated.h 라고 적힌 저 수상한 path를 찾아 들어가봤다.

 

 

define이 상당히 많아서 엔진코드다. 라고 넘기려는데 익숙한 함수 이름이 보여서 확인해봤다. execOnClickedTab이라고 되어있는 저부분은 내가 실제 UMG_Tab.h 에 UFUNCTION으로 지정해둔 함수명이다.

 

 

실제 UMG_Tab.h의 함수를 리플렉션 하고 있다는게 이런 뜻인가.. 감이 올 듯 말 듯 했다. UFUNCTION을 이용해서 블루프린트에서도 c++ 코드를 사용할 수 있도록 했으니 리플렉션을 사용했다. 라고 이해를 해보았다.

 

언리얼 문서에 이런 내용이 있었다.

 

 

위의 내용을 뜯으면 이렇다.

 

- UnrealBuildTool 이라는 곳에서 리플렉션 키워드를 찾는다. 그리고 그 모듈을 기억하고 있는다.

- 이전 컴파일 했던 내용과 다른 내용이 발생하면 언리얼 헤더 툴(UHT)을 실행한다.

- 리플렉션 데이터를 수집한다. 

- 수집한 정보를 별도로 .generated.h / .generated.cpp로 저장한다. (아마 여기서 에디터에서 코드에 접근할 수 있도록 리플렉션 된 내용이 작성되는 것 같다.)

 

 

변수도 확인해봤다. 버튼클래스와 int32 자료형의 TabID를 UPROPERTY 매크로를 넣고 .generated.h/ .generated.cpp를 찾아 들어가봤다.

 

UUMG_Tab.generated.h에서는 변수와 관련된 내용은 못 찾았다. 그래서 cpp를 봤더니

 

 

이런식으로 뭔가 Button 클래스와 TabID에 대해서 저장 되고 있는 것 같았다.

 

그래서 다시 TabID의 UPROPERTY 매크로를 지워봤다.

 

 

그리고 gen.cpp로 들어갔더니

 

감쪽같이 TabID 에 대한 메타 데이터가 제거됐다. 

 

참고로 코드 변경 후 F5로 컴파일을 하면

저기 보이는 init.gen.cpp , gen.cpp , cpp 이렇게 빌드가 이루어진다.  이 과정에서 UPROPERTY에 대한 변화를 감지하고 헤더툴을 실행해서 리플렉션 데이터를 수집한 뒤 그 데이터를 gen.h / gen.cpp에 반영해서 블루프린트에 연동 되거나 혹은 가비지 컬렉터에서 수집할 수 있도록 제공되는 것 같다. 

 

가비지 컬렉터에 관해서도 조금 더 파헤쳐보고 포스팅해야겠다.