Unreal Engine Reflection System: How It Handles Types at Runtime
Unreal Engine relies on its own reflection system to access type information during runtime. This powers object serialization, property display in the editor, C++ and Blueprint integration, and network communication. The system is built on code generation via the Unreal Header Tool and two parallel type hierarchies.
Reflection Architecture: UHT and Generated Files
The Unreal Header Tool (UHT) scans C++ header files, spots macros like UCLASS and UPROPERTY, and generates code to register types. This creates two key files:
- .generated.h — holds macros and forward declarations.
- .gen.cpp — contains type registration code that can span thousands of lines.
The generated code stores metadata like property names, flags, and memory offsets. For instance, the CurrentValue property in FAbilityAttribute has its offset registered via STRUCT_OFFSET, letting the engine access data directly at runtime.
Two Type Hierarchies: UObject and FField
UE5 uses two systems to describe types, split for performance optimization.
UObject-Based Hierarchy
Managed by the garbage collector, this includes:
- UClass for C++ classes.
- UFunction for functions.
- UScriptStruct for structs.
- UEnum for enums.
FField-Based Hierarchy
Introduced in UE 4.25 to cut overhead, properties here skip garbage collection:
- FField — base class.
- FProperty — describes individual properties, like FIntProperty or FFloatProperty.
- Link between hierarchies: UStruct holds a pointer to a linked list of FField properties.
Key FField features:
- Uses a linked list for child elements.
- Includes FFieldClass with fast type casting via bitmasks.
- FFieldVariant combines UObject and FField pointers, using the low bit to distinguish types.
Anatomy of FProperty: Accessing Data
FProperty provides tools for handling properties in memory. Core elements:
- Offset_Internal — property's memory offset, calculated via STRUCT_OFFSET.
- EPropertyFlags — flags dictating behavior, like CPF_Edit for editor tweaks.
- Access methods like ContainerPtrToValuePtr for direct read/write.
Example in action:
UAbilityComponent* Comp = ...;
FProperty* HealthProp = Comp->GetClass()->FindPropertyByName(TEXT("HealthAttribute"));
FAbilityAttribute* HealthPtr = HealthProp->ContainerPtrToValuePtr<FAbilityAttribute>(Comp);
float CurrentHealth = HealthPtr->CurrentValue;
Practical Uses of Reflection
Unreal Engine's reflection system drives key features:
- Serialization — saving and loading objects from files.
- Editor — displaying properties in the Details panel with categories and custom widgets.
- Blueprint Integration — exposing C++ properties and functions to visual scripting.
- Network Replication — syncing data between client and server.
- Garbage Collection — tracking object ownership for memory management.
Key Takeaways
- Unreal Engine reflection relies on Unreal Header Tool code generation, not native C++ features.
- Splitting UObject and FField hierarchies boosts performance and memory handling.
- Memory offsets in FProperty enable fast runtime data access.
- The system underpins core engine functions like serialization, editing, and networking.
- Mastering reflection is essential for building advanced systems like ability components or custom editor tools.
— Editorial Team
No comments yet.