17 UE5 UObject的反射实现和调用

2024-03-14  本文已影响0人  游戏开发程序员

C#中的反射

image.png
  1. Assembly程序集,通常指的是一个dll。
  2. Module是程序集内部的子模块。
  3. Type就是Class对象,完整描述了一个对象的类型信息。
  4. ConstructorInfo描述了Type中的构造函数,可用它来调用特定的构造函数。
  5. EventInfo描述了Type中定义的event事件(UE中的delegate)
  6. FiedInfo描述了Type中的字段,就是C++的成员变量,可以动态读取修改值
  7. PropertyInfo描述了Type中的属性,get/set方法组合,得到后可以获取设置属性值。
  8. MethodInfo描述了Type中的方法。可以动态调用。
  9. ParameterInfo描述了方法中的参数。
  10. Attributes指的是Type之上附加的特性,为类上的定义的元数据信息(C++没有)。

C++RTTI反射库 rttr

#include <rttr/registration>
using namespace rttr;
struct MyStruct { MyStruct() {}; void func(double) {}; int data; };
RTTR_REGISTRATION
{
    registration::class_<MyStruct>("MyStruct")
         .constructor<>()
         .property("data", &MyStruct::data)
         .method("func", &MyStruct::func);
}

QT的反射

举个例子

1 比如MOC工具读取C++源文件,发现类的定义里有Q_OBJECT宏,
2 它就会为这个类生成另外一个包含有元对象支持代码的c++源文件,
3 这个生成的源文件连同类里的实现文件一起被编译和连接。

#include <QObject>
class MyClass : public QObject
{
    Q_OBJECT
  Q_PROPERTY(int Member1 READ Member1 WRITE setMember1 )
  Q_PROPERTY(QString MEMBER3 READ Member3 WRITE setMember3 )
  public:
      explicit MyClass(QObject *parent = 0);
  signals:
  public slots:
  public:
    Q_INVOKABLE int Member1();
    Q_INVOKABLE QString Member3();
    Q_INVOKABLE void setMember1( int mem1 );
    Q_INVOKABLE void setMember3( const QString& mem3 );
    Q_INVOKABLE int func( QString flag );
  private:
    int m_member1;
    QString m_member3;
 };

UE里UHT的方案

UCLASS()
class UTestObject : public UObject
{
    GENERATED_BODY()

public:
    UPROPERTY(BlueprintReadWrite, Category = "Test")
    FString CurPlayerName;

    UPROPERTY(BlueprintReadWrite, Category = "Test")
    int32 CurPlayerAge;

    UFUNCTION(BlueprintCallable, Category = "Test")
    FString GetOutInfo();
};

generated文件和UML图

image.png

UHT对函数的3个类别支持

UFUNCTION(BlueprintCallable)
bool IsBoy(); // 需要函数定义
// UHT会自动声明exec前缀函数
DECLARE_FUNCTION(execIsBoy);

UFUNCTION(BlueprintNativeEvent)
bool IsGirl();
// 函数名定义为: bool UMyObject::IsGirl_Implementation()
// UHT会自动声明exec前缀函数
DECLARE_FUNCTION(execIsGirl); 
......

        // StaticClass中的注册函数
    void UTestObject::StaticRegisterNativesUTestObject()
    {
        UClass* Class = UTestObject::StaticClass();
        static const FNameNativePtrPair Funcs[] = {
            { "GetOutInfo", &UTestObject::execGetOutInfo },
            { "IsBoy", &UTestObject::execIsBoy },
            { "IsGirl", &UTestObject::execIsGirl },
        };
        FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, UE_ARRAY_COUNT(Funcs));
    }
    DEFINE_FUNCTION(UMyObject::execIsBoy)
    {
        P_FINISH;
        P_NATIVE_BEGIN;
        *(bool*)Z_Param__Result=P_THIS->IsBoy();
        P_NATIVE_END;
    }

    DEFINE_FUNCTION(UMyObject::execIsGirl)
    {
        P_FINISH;
        P_NATIVE_BEGIN;
        *(bool*)Z_Param__Result=P_THIS->IsGirl_Implementation();
        P_NATIVE_END;
    }

    UFUNCTION(BlueprintImplementableEvent)
    bool IsBaBy();
      
        // UHT对IsBaBy 和 IsGirl
    static FName NAME_UMyObject_IsBaBy = FName(TEXT("IsBaBy"));
    bool UMyObject::IsBaBy()
    {
        MyObject_eventIsBaBy_Parms Parms;
        ProcessEvent(FindFunctionChecked(NAME_UMyObject_IsBaBy),&Parms);
        return !!Parms.ReturnValue;
    }
    static FName NAME_UMyObject_IsGirl = FName(TEXT("IsGirl"));
    bool UMyObject::IsGirl()
    {
        MyObject_eventIsGirl_Parms Parms;
        ProcessEvent(FindFunctionChecked(NAME_UMyObject_IsGirl),&Parms);
        return !!Parms.ReturnValue;
    }

Z_Construct_UClass_UTestObject_Statics 统计属性

static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[];

    const UECodeGen_Private::FIntPropertyParams Z_Construct_UClass_UTestObject_Statics::NewProp_CurPlayerAge = 
{ "CurPlayerAge", nullptr, (EPropertyFlags)0x0010000000000004, UECodeGen_Private::EPropertyGenFlags::Int, 
RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(UTestObject, CurPlayerAge), 
METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UClass_UTestObject_Statics::NewProp_CurPlayerAge_MetaData), 
Z_Construct_UClass_UTestObject_Statics::NewProp_CurPlayerAge_MetaData) };
    
const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_UTestObject_Statics::PropPointers[] = {
        (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_UTestObject_Statics::NewProp_CurPlayerName,
        (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_UTestObject_Statics::NewProp_CurPlayerAge,
    };

Z_Construct_UClass_UTestObject_Statics 统计函数

    const FClassFunctionLinkInfo Z_Construct_UClass_UTestObject_Statics::FuncInfo[] = {
        { &Z_Construct_UFunction_UTestObject_GetOutInfo, "GetOutInfo" }, // 3640447053
        { &Z_Construct_UFunction_UTestObject_IsBaBy, "IsBaBy" }, // 271090006
        { &Z_Construct_UFunction_UTestObject_IsBoy, "IsBoy" }, // 369736746
        { &Z_Construct_UFunction_UTestObject_IsGirl, "IsGirl" }, // 4061052473
    };

获取UObject中的成员变量

// 反射功能 获取反射生成的类StaticClass
        UClass* pStaticClass = pObj->GetClass();
        if(pStaticClass)
        {
            // 获取字段指针
            FProperty* pProperty = pStaticClass->FindPropertyByName(FName(TEXT("CurPlayerName")));
            // 转换为对应的字段类型 static_cast
            FStrProperty* pStrProp = CastField<FStrProperty>(pProperty);
            if(pStrProp)
            {
                // 从UObject中的属性数组中获取属性指针
                void* pValue = pStrProp->ContainerPtrToValuePtr<void>(pObj);
                // 获取属性值
                FString Name = pStrProp->GetPropertyValue(pValue);
                // 修改属性值
                pStrProp->SetPropertyValue(pValue, TEXT("Bill"));
            }
        }

获取UObject中的成员函数

            // 获取函数指针
            UFunction* pFunc = pStaticClass->FindFunctionByName(FName(TEXT("GetOutInfo")));
            if(pFunc)
            {
                // 传入参数和返回值结构体
                struct Func_Parms   
                {
                    FString Caller;
                    FString ReturnValue;
                };
                Func_Parms args;
                args.Caller = TEXT("Test");
                // 调用
                pObj->ProcessEvent(pFunc, &args);
                // 打印返回
                UE_LOG(TestLog, Warning, TEXT("%s"), *args.ReturnValue);
            }
上一篇 下一篇

猜你喜欢

热点阅读