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에 반영해서 블루프린트에 연동 되거나 혹은 가비지 컬렉터에서 수집할 수 있도록 제공되는 것 같다.
가비지 컬렉터에 관해서도 조금 더 파헤쳐보고 포스팅해야겠다.
'UnrealEngine > 언리얼' 카테고리의 다른 글
[UE5] GAS / AbilitySystemComponent 겉핥기 (0) | 2023.04.17 |
---|---|
[UE5] GAS / GameplayAbility 게임플레이 어빌리티 (0) | 2023.04.14 |
[UE5] GAS / GameAbilitySystem 겉핥기(feat. Lyra) (0) | 2023.04.03 |
[UE5] C++ fatal error C1083: 포함 파일을 열 수 없습니다. (0) | 2022.12.27 |