나만의 작은 도서관
[언리얼] Unreal Header Tool(UHT) 본문
Unreal Header Tool(UHT)란?
- Unreal Header Tool(이하 UHT)이란 C++ 소스 코드들을 빌드하기 전에 언리얼 리플렉션 시스템에 필요한 정보들을 읽는 작업을 하는 툴(Tool)로, 언리얼 프로젝트와 연동된 MSVC에서 빌드 시 자동으로 실행된다. (라이브 코딩 비활성화 기준)
UHT 실행 과정
- 헤더 파일 스캔: UBT(Unreal Build Tool)가 소스 파일 중 리플렉션 키워드(ex. UCLASS, EditAnywhere)가 들어있는 헤더 파일(. h)을 탐색
- UBT가 헤더 파일에서 리플렉션 키워드를 발견했다면 UHT 호출
- 파싱 및 분석: UHT는 해당 헤더 파일(.h)을 파싱 하여 리플렉션 데이터(클래스, 구조체, 함수, 메타데이터)를 추출 및 수집
- 코드 생성: 각 헤더 파일에 대응하는 “xxx.generated.h”, “xxx.gen.cpp”를 생성
- 이때 생성된 코드는 “런타임”에 UClass, Ustruct, UFunction 등의 객체로 변환된다.
- ⇒ 이를 통해 블루프린트 시스템, 직렬화(Serialization), 가비지 컬렉션이 작동한다.
- 컴파일러 빌드 시작: UHT가 만든 코드와 함께 소스 코드가 빌드된다.
+) 참고로 UHT가 실행될때마다 Intermediate 폴더도 갱신된다.
UHT가 생성한 정적 함수 StaticXXX()
- UHT가 생성한 xxx.generated.h 파일에는 정적 함수인 StaticXXX() 시리즈가 있다. 이 시리즈들을 통해 런타임 리플렉션 정보에 접근할 수 있다.
// AMyActor.generated.h에서 생성되는 코드 예시
class AMyActor {
public:
static UClass* StaticClass() {
static UClass* StaticClassPtr = nullptr;
if (!StaticClassPtr) {
StaticClassPtr = UObject::GetStaticClass(/* ... */);
}
return StaticClassPtr;
}
};
예시 1. StaticClass()
- UCLASS 매크로가 적용된 모든 클래스에 대해 자동으로 생성되는 정적 함수.
- 반환값으로 해당 클래스의 UClass* 객체를 반환한다.
- UClass는 클래스의 메타데이터(metadata)를 담고 있는 리플렉션 객체
// 활용 1. "AMyActor" 클래스의 UClass 정보를 가져온다.
UClass* MyActorClass = AMyActor::StaticClass();
// 활용 2. 새로운 "AMyActor" 객체를 생성할때 사용한다.
AActor* NewActor = GetWorld()->SpawnActor<AActor>(AMyActor::StaticClass());
// 활용 3. 특정 객체가 "AMyActor" 타입인지 확인할 때 사용한다.
if(SomeObject->GetClass() == AMyActor::StaticClass()){
}
// 활용 4. 특정 객체가 "AMyAcotr" 또는 그 자식 클래스인지 확인할 때 사용한다.
if(SomeObject->IsA(AMyActor::StaticClass()){
}
예시 2. StaticStruct()
- USTRUCT 매크로가 적용된 모든 구조체에 대해 자동으로 생성되는 정적 함수
- 반환값으로 해당 구조체의 UStruct* 객체를 반환한다.
- UStruct는 구조체의 메타데이터(metadata)를 담고 있는 리플렉션 객체
// 구조체를 USTRUCT로 지정
USTRUCT(BlueprintType)
struct FMyStruct {
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite)
int32 Value;
};
// 활용 1. "FMyStruct" 구조체의 UStruct 정보를 가져온다.
UStruct* MyStructType = FMyStruct::StaticStruct();
// "FMyStruct" 구조체 속성(멤버 변수)을 가져온다.
UProperty* ValueProperty = MyStructType->FindPropertyByName("Value");
왜 UFUNCTION, UPROPERTY와 같은 리플렉션 매크로 함수를 붙이는가?
- 해당 요소(함수나 변수 등)를 에디터에 노출시키기 위해서
- 해당 요소를 블루프린트에서 사용하기 위해서
- 해당 요소를 런타임에 타입 정보를 알고 싶어서
- 해당 요소를 GC(Garbage Collection)에 추가하고 싶어서
- 해당 요소를 네트워크 동기화 처리를 맡기고 싶어서
리플렉션 매크로 함수의 지정자(Specifiers)
- UFUNCTION, UPROPERTY와 같은 리플렉션 매크로 함수들에 지정자를 추가할 수 있다. 개발자는 지정자를 추가함으로써 여러 고급 기능들을 활용할 수 있게 된다.
클래스(UCLASS) 지정자 예시
| 지정자 이름 | 설명 |
| BlueprintType | 이 클래스를 “블루프린트에서 변수로 사용할 수 있는 타입”으로 지정한다. |
| Blueprintable | 이 클래스를 “블루프린트에서 생성할 수 있는 기반 클래스”로 지정한다. |
| Abstract | 클래스를 “추상 베이스 클래스”로 선언. 사용자가 해당 클래스 액터를 월드에 추가하지 못하도록 한다. |
속성(UPROPERTY) 지정자 예시
- UPROPERTY로 설정한 변수는 언리얼 에디터의 디테일 패널에 노출 여부를 결정할 수 있다. (유니티의 [SerializeField]랑 비슷한 듯?)
| 지정자 이름 | 설명 |
| EditAnywhere | 이 프로퍼티를 아키타입이나 인스턴스 양쪽의 프로퍼티 창에서 편집할 수 있도록 한다. |
| BlueprintReadOnly | 이 프로퍼티를 블루프린트에서 읽을 수 있도록 한다. |
| BlueprintReadWrite | 이 프로퍼티를 블루프린트에서 읽거나 쓸 수 있도록 한다. |
| Replicated | 이 프로퍼티가 네트워크를 통해 리플리케이트 되도록 한다. |
| SaveGame | 프로퍼티 레벨에서 체크포인트/저장 시스템용 필드를 명시적으로 포함시키도록 한다. |
함수(UFUNCTION) 지정자 예시
- UFUNCTION으로 설정한 함수는 블루프린트에서 호출 가능 여부를 결정할 수 있다.
| 지정자 이름 | 설명 |
| BlueprintCallable | 이 함수를 블루프린트에서 “호출 가능”하도록 한다. |
| BlueprintImplementableEvent | 이 함수를 블루프린트에서 구현하는 이벤트로 지정한다. |
| CallInEditor | 이 함수를 에디터에서도 실행 가능하도록 한다. |
| Server/Client | 이 함수를 네트워크 RPC 함수로 지정한다. |
기타 지정자
| 지정자 이름 | 설명 |
| Category | 드롭다운 리스트의 토글 목록을 추가한다.(ex. Category = “Login” → Login 토글 목록이 생김) |
언리얼에서 메타데이터(metadata)란?
- 언리얼 엔진에서 메타데이터(metadata)는 에디터에만 존재하는 데이터로, 클래스, 구조체, 함수, 프로퍼티에 대한 추가적인 정보들을 의미한다.
- 즉, 메타데이터는 코드 자체의 동작과는 별개이며, 에디터나 런타임 시스템이 해당 요소를 어떻게 다뤄야 하는지 결정하는 정보들이다.
- 메타데이터는 리플렉션 키워드 매크로의 지정자(Specifiers)로 추가할 수 있으며, 추가하는 방법은 아래와 같이 “meta”라는 단어와 그 뒤에 지정자 목록과 필요한 값을 적어주면 된다.
UFUNCTION(BlueprintCallable, Category="MyGame|Combat",
meta=(DisplayName="Deal Damage", ToolTip="Applies damage to target",
Keywords="damage hurt attack"))
void DealDamage(float DamageAmount);
실제 사용 예시
UCLASS(BlueprintType, Blueprintable) // <- 지정자들
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Movement", // <- 지정자들
meta=(DisplayName="Max Speed", // <- 메타데이터 시작
ToolTip="Maximum movement speed in units per second",
UIMin="0.0", UIMax="1000.0",
ClampMin="0.0")) // <- 메타데이터 끝
float MaxSpeed = 600.0f;
UFUNCTION(BlueprintCallable, Category="Movement") // <- 지정자들
void SetSpeed(float NewSpeed);
};
런타임 접근 방법
지정자 정보: UClass의 플래그나 프로퍼티 플래그로 접근
// EditAnywhere 지정자 확인
bool bCanEdit = Property->HasAnyPropertyFlags(CPF_Edit);
메타데이터: GetMetaData() 함수로 접근
// DisplayName 메타데이터 확인
FString DisplayName = Property->GetMetaData("DisplayName");
'Unreal Engine' 카테고리의 다른 글
| [언리얼] 라이브 코딩(Live Coding)이란? (0) | 2026.05.14 |
|---|---|
| [Unreal Engine] 언리얼 프로젝트 폴더 이동 시, 최근 프로젝트에 프로젝트가 뜨지 않는 문제 해결법 (0) | 2025.02.08 |
| [Unreal Engine] unreal gpu crashed or d3d device removed 해결법 (1) | 2025.02.08 |
