StoneのBLOG

生活这种事情,从来都是自我陶醉

0%

UE4-反射机制

反射在其它的比如说C#,JAVA语言中比较常见。反射概况的来说是描述类在运行时的状态,反射中包含的信息有类名,类数据成员,数据成员类型,还有每个成员位于对象内存映像的偏移(offset),类所有成员函数的信息。

C++本身是不支持反射的,4在C++的基础上搭建了自己的一套反射机制。

UE4的反射机制原理

Property system的层级

1
2
3
4
5
6
7
8
9
10
11
UField
UStruct
UClass (C++ class)
UScriptStruct (C++ struct)
UFunction (C++ function)

UEnum (C++ enumeration)

UProperty (C++ member variable or function parameter)

(Many subclasses for different types)

上面的文章虽然是很久之前文章,但是还是很厉害。

利用反射对属性进行读写

最近在搞使用ImGui对ini文件进行读写的功能,同时又希望像UE4的Editor那样,对于添加的UCLASS的类中的UPROPERTY属性自动的显示各种类型的UI。于是就研究了一下反射,虽然原理什么的我还是不是很清楚,希望能多读读上面的文章而不是只是单纯的记录下来,终归动还是能动的。

直接贴上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Debug settings UI
bool show_about_app = true;
ImGui::Begin("DebugSettings", &show_about_app, ImGuiWindowFlags_AlwaysAutoResize);

// Creaete DebugUI for UObject
bool AnyPropertiesEdited = false;
UClass* obj = DebugSettings->GetClass();
for(TFieldIterator<FProperty> PropertyIterator(obj); PropertyIterator; ++PropertyIterator)
{
FProperty* Property = *PropertyIterator;
if(FBoolProperty* BoolProperty = CastField<FBoolProperty>(Property))
{
// UE_LOG(LogTemp, Log, TEXT("cast bool property successed."));
static bool sampleBool = BoolProperty->GetPropertyValue_InContainer(DebugSettings);
ImGui::Checkbox(TCHAR_TO_ANSI(*BoolProperty->GetName()), &sampleBool);
if(ImGui::IsItemEdited())
{
// Apply changes
BoolProperty->SetPropertyValue(BoolProperty->ContainerPtrToValuePtr<bool>(DebugSettings), sampleBool);
AnyPropertiesEdited = true;
}
}
else if(FIntProperty* IntProperty = CastField<FIntProperty>(Property))
{
// UE_LOG(LogTemp, Log, TEXT("cast int property successed."));
static int sampleInt = IntProperty->GetPropertyValue_InContainer(DebugSettings);
ImGui::InputInt(TCHAR_TO_ANSI(*IntProperty->GetName()), &sampleInt);
if(ImGui::IsItemEdited())
{
// Apply changes
IntProperty->SetPropertyValue(IntProperty->ContainerPtrToValuePtr<int>(DebugSettings), sampleInt);
AnyPropertiesEdited = true;
}
}
else if(auto StrProperty = CastField<FStrProperty>(Property))
{
FString sampleStr = StrProperty->GetPropertyValue_InContainer(DebugSettings);
// TODO:
}
}
if(AnyPropertiesEdited)
{
DebugSettings->SaveConfig();
}

ImGui::End();

没有对应所有的类型,但是知道了方法就行了。

这其中有一篇文章很重要:

UE4.25版本更改了UProperty->FProperty,跟之前写法会有些出入

还参考了其他人的提问的文章

利用反射对函数进行操作

有一天突发奇想,UE4的反射机制可不可以遍历UObject中的UFUNCTION?然后根据UUFUNCTION的的类型,比如说根据Meta修饰符来切换ImmGui的UI类型,Button啥的。

遍历UFUNCTION貌似是可行的:

1
2
3
4
5
6
7
8
9
void UMyClass::ListAllObjectUFunctions(const UObject* Object) {

for ( TFieldIterator<UFunction> FIT ( Object->GetClass(), EFieldIteratorFlags::IncludeSuper ); FIT; ++FIT) {

UFunction* Function = *FIT;
UE_LOG ( LogTemp, Log, TEXT( "Function Found: %s();" ), *Function->GetName() );

}
}

至于自定义的Meta修饰符,我还没开始调查。啧。

参考资料

感觉上面的文章都很重要。尤其是最后一篇。