想让类具有反射机制,必须要有这四个要素:
1、generated.h文件
2、UCLASS()宏
3、继承自UObject
4、GENERATED_BODY()
void ABlurCharacter::BeginPlay()
{
Super::BeginPlay();
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
FName BlurCharacterName = BlurCharacterClass->GetFName();
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, *BlurCharacterName.ToString());
}
这样就将类名给输出出来了
for(UProperty *Per = BlurCharacterClass->PropertyLink; Per; Per = Per->PropertyLinkNext)
{
if(Per->GetCPPType() == TEXT("FString"))
{
UStrProperty *Str = Cast<UStrProperty>(Per); //转化为Str类型的属性
void *Addr = Str->ContainerPtrToValuePtr<void>(BlurCharacter); //从容器信息转变成具体值
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Yellow, Per->GetName() + TEXT(" ------ ") + Per->GetCPPType() +
TEXT(" ------ ") + Str->GetPropertyValue(Addr));
Str->SetPropertyValue(Addr, "AfterModified");
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Yellow, Per->GetName() + TEXT(" ------ ") + Per->GetCPPType() +
TEXT(" ------ ") + Str->GetPropertyValue(Addr));
}
}
UPROPERTY()
FString Hello = "Hello World";
获取类中FString类型的值、类型、和名称,根据代码可以看出,存储变量的数据结构是一个链表,注意,变量一定要用UPROPERTY()给包裹,不然不会将变量信息反射到链表,更不可能存取这些信息
for(TFieldIterator<UFunction> Iter(BlurCharacterClass); Iter; ++Iter)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Blue, Iter->GetName());
for(TFieldIterator<UProperty> Iter1(*Iter); Iter1; ++Iter1)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Black, Iter1->GetName() + TEXT(" ------ ") + Iter1->GetCPPType());
}
}
同理,自己写的函数也必须加入UFUNCTION()
void ABeginInvokeGameModeBase::BeginPlay() {
Super::BeginPlay();
AAFloorSwitch* FloorSwitch = NewObject<AAFloorSwitch>();
UClass* Father = FloorSwitch->GetClass()->GetSuperClass();
FString Name = Father->GetName();
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, Name);
}
UCLASS()
class MYCTEST_API AAFloorSwitch : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AAFloorSwitch();
}
在GameMode进行获取父类,在Actor内获取被隐藏
判断一个类是否是另一个类的父类
查找一个类的所有子类,第三个参数是找是否找子类的类,是否递归去找
AAFloorSwitch* swithc = NewObject<AAFloorSwitch>(this, FName("Tiger"));
TArray<UObject*> Res;
GetObjectsOfClass(StaticClass(), Res, false);
for (auto Actor : Res) {
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Yellow, Actor->GetName());
}
GetObjectsOfClass():去查找实例化出来的变量的个数
UClass *FoundClass = FindObject<UClass>(ANY_PACKAGE, *FString("ABlurCharacter"), true);
if(FoundClass->IsValidLowLevel())
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Black, FoundClass->GetName());
}
通过名字去查找类名
UEnum *FoundEnum = FindObject<UEnum>(ANY_PACKAGE, *FString("EMyEnum"), true);
if(FoundEnum->IsValidLowLevel())
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Orange, FoundEnum->GetName());
}
UENUM()
enum class EMyEnum : uint8
{
ONE,
TWO,
THREE
};
通过名字查找枚举
ANY_PACKAGE是代表在每一文件夹下去查找是否有这个名字的相关值
UEnum *FoundEnum = FindObject<UEnum>(ANY_PACKAGE, *FString("EMyEnum"), true);
if(FoundEnum->IsValidLowLevel())
{
//GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Orange, FoundEnum->GetName());
for(int32 Index = 0; Index < FoundEnum->NumEnums(); Index++)
{
FString FoundEnumChild = FoundEnum->GetNameStringByIndex(Index);
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Orange, FoundEnumChild);
}
}
UENUM()
enum class EMyEnum : uint8
{
ONE,
TWO,
THREE
};
通过枚举获取枚举内所有属性名字,EMyEnum_MAX其实是用于统计枚举内最大数值的,源代码是这么写的:
int64 UEnum::GetMaxEnumValue() const
{
int32 NamesNum = Names.Num();
if (NamesNum == 0)
{
return 0;
}
int64 MaxValue = Names[0].Value;
for (int32 i = 0; i < NamesNum; ++i)
{
int64 CurrentValue = Names[i].Value;
if (CurrentValue > MaxValue)
{
MaxValue = CurrentValue;
}
}
return MaxValue;
}
如何输出这个值呢:
UEnum *FoundEnum = FindObject<UEnum>(ANY_PACKAGE, *FString("EMyEnum"), true);
if(FoundEnum->IsValidLowLevel())
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Orange, FString::SanitizeFloat(FoundEnum->GetMaxEnumValue()));
}
UBlueprint *BlueprintClass = FindObject<UBlueprint>(ANY_PACKAGE, *FString("BP_MainWidget"));
if(BlueprintClass->IsValidLowLevel())
{
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, BlueprintClass->GetName());
}
如何通过蓝图名称找到蓝图类
UBlueprint *BlueprintClass = FindObject<UBlueprint>(ANY_PACKAGE, *FString("BP_MainWidget"));
if(BlueprintClass->IsValidLowLevel())
{
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, BlueprintClass->GetName());
if(BlueprintClass->IsNative())
{
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, TEXT("YES"));
}else
{
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, TEXT("NO"));
}
}
判断此类是蓝图类还是C++类,Native就是C++类
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
for(UProperty *Per = BlurCharacterClass->PropertyLink; Per; Per = Per->PropertyLinkNext)
{
if(Per->GetCPPType() == TEXT("FString"))
{
UStrProperty *Str = Cast<UStrProperty>(Per);
FString CategoryStr = Str->GetMetaData(TEXT("Category"));
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, CategoryStr);
}
}
UPROPERTY(EditAnywhere, Category = "Hello")
FString Hello = "Hello World";
获取元数据信息
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
for(TFieldIterator<UFunction> Iter(BlurCharacterClass); Iter; ++Iter)
{
uint32 Flags = Iter->FunctionFlags;
if(Iter->GetName() == TEXT("GetMousePixel"))
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Blue, FString::FromInt(Flags));
}
UFUNCTION(BlueprintCallable)
FColor GetMousePixel();
查找到数值为75629569,那么从第一位开始看为9,只能由1和8组成,所以兼备FUNC_Final和FUNC_BlueprintCosmetic的属性,即该方法为Final方法,此方法不能被继承,且该方法不能被服务端调用
再看第二位60只能由//FUNC_与FUNC_Net组成,第一个无用,没有功能,第二个该方法可被网络复制
我们直接看第七位,为5,只能由FUNC_NetClient与FUNC_BlueprintCallable组成,第一个为该函数可在客户端进行执行,第二个就是经常用到的BlueprintCallable了,如上方代码所对应
其它位数都是依次类推
enum EFunctionFlags
{
// Function flags.
FUNC_Final = 0x00000001, // Function is final (prebindable, non-overridable function).
FUNC_RequiredAPI = 0x00000002, // Indicates this function is DLL exported/imported.
FUNC_BlueprintAuthorityOnly= 0x00000004, // Function will only run if the object has network authority
FUNC_BlueprintCosmetic = 0x00000008, // Function is cosmetic in nature and should not be invoked on dedicated servers
// FUNC_ = 0x00000010, // unused.
// FUNC_ = 0x00000020, // unused.
FUNC_Net = 0x00000040, // Function is network-replicated.
FUNC_NetReliable = 0x00000080, // Function should be sent reliably on the network.
FUNC_NetRequest = 0x00000100, // Function is sent to a net service
FUNC_Exec = 0x00000200, // Executable from command line.
FUNC_Native = 0x00000400, // Native function.
FUNC_Event = 0x00000800, // Event function.
FUNC_NetResponse = 0x00001000, // Function response from a net service
FUNC_Static = 0x00002000, // Static function.
FUNC_NetMulticast = 0x00004000, // Function is networked multicast Server -> All Clients
// FUNC_ = 0x00008000, // unused.
FUNC_MulticastDelegate = 0x00010000, // Function is a multi-cast delegate signature (also requires FUNC_Delegate to be set!)
FUNC_Public = 0x00020000, // Function is accessible in all classes (if overridden, parameters must remain unchanged).
FUNC_Private = 0x00040000, // Function is accessible only in the class it is defined in (cannot be overridden, but function name may be reused in subclasses. IOW: if overridden, parameters don't need to match, and Super.Func() cannot be accessed since it's private.)
FUNC_Protected = 0x00080000, // Function is accessible only in the class it is defined in and subclasses (if overridden, parameters much remain unchanged).
FUNC_Delegate = 0x00100000, // Function is delegate signature (either single-cast or multi-cast, depending on whether FUNC_MulticastDelegate is set.)
FUNC_NetServer = 0x00200000, // Function is executed on servers (set by replication code if passes check)
FUNC_HasOutParms = 0x00400000, // function has out (pass by reference) parameters
FUNC_HasDefaults = 0x00800000, // function has structs that contain defaults
FUNC_NetClient = 0x01000000, // function is executed on clients
FUNC_DLLImport = 0x02000000, // function is imported from a DLL
FUNC_BlueprintCallable = 0x04000000, // function can be called from blueprint code
FUNC_BlueprintEvent = 0x08000000, // function can be overridden/implemented from a blueprint
FUNC_BlueprintPure = 0x10000000, // function can be called from blueprint code, and is also pure (produces no side effects). If you set this, you should set FUNC_BlueprintCallable as well.
// FUNC_ = 0x20000000, // unused.
FUNC_Const = 0x40000000, // function can be called from blueprint code, and only reads state (never writes state)
FUNC_NetValidate = 0x80000000, // function must supply a _Validate implementation
// Combinations of flags.
FUNC_FuncInherit = FUNC_Exec | FUNC_Event | FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_BlueprintAuthorityOnly | FUNC_BlueprintCosmetic,
FUNC_FuncOverrideMatch = FUNC_Exec | FUNC_Final | FUNC_Static | FUNC_Public | FUNC_Protected | FUNC_Private,
FUNC_NetFuncFlags = FUNC_Net | FUNC_NetReliable | FUNC_NetServer | FUNC_NetClient | FUNC_NetMulticast,
FUNC_AccessSpecifiers = FUNC_Public | FUNC_Private | FUNC_Protected,
FUNC_AllFlags = 0xFFFFFFFF,
};
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
uint32 ClassFlags = BlurCharacterClass->ClassFlags;
GEngine->AddOnScreenDebugMessage(-1, 10.f ,FColor::Red, FString::FromInt(ClassFlags));
同理:这样就可以获取一些与类相关的信息
enum EClassFlags
{
/** @name Base flags */
//@{
CLASS_None = 0x00000000,
/** Class is abstract and can't be instantiated directly. */
CLASS_Abstract = 0x00000001,
/** Save object configuration only to Default INIs, never to local INIs. Must be combined with CLASS_Config */
CLASS_DefaultConfig = 0x00000002,
/** Load object configuration at construction time. */
CLASS_Config = 0x00000004,
/** This object type can't be saved; null it out at save time. */
CLASS_Transient = 0x00000008,
/** Successfully parsed. */
CLASS_Parsed = 0x00000010,
/** */
//CLASS_ = 0x00000020,
/** All the properties on the class are shown in the advanced section (which is hidden by default) unless SimpleDisplay is specified on the property */
CLASS_AdvancedDisplay = 0x00000040,
/** Class is a native class - native interfaces will have CLASS_Native set, but not RF_MarkAsNative */
CLASS_Native = 0x00000080,
/** Don't export to C++ header. */
CLASS_NoExport = 0x00000100,
/** Do not allow users to create in the editor. */
CLASS_NotPlaceable = 0x00000200,
/** Handle object configuration on a per-object basis, rather than per-class. */
CLASS_PerObjectConfig = 0x00000400,
/** pointers to this class default to weak. */
CLASS_PointersDefaultToWeak = 0x00000800,
/** Class can be constructed from editinline New button. */
CLASS_EditInlineNew = 0x00001000,
/** Display properties in the editor without using categories. */
CLASS_CollapseCategories = 0x00002000,
/** Class is an interface **/
CLASS_Interface = 0x00004000,
/** Do not export a constructor for this class, assuming it is in the cpptext **/
CLASS_CustomConstructor = 0x00008000,
/** all properties and functions in this class are const and should be exported as const */
CLASS_Const = 0x00010000,
/** pointers to this class default to weak. */
CLASS_PointersDefaultToAutoWeak = 0x00020000,
/** Indicates that the class was created from blueprint source material */
CLASS_CompiledFromBlueprint = 0x00040000,
/** Indicates that only the bare minimum bits of this class should be DLL exported/imported */
CLASS_MinimalAPI = 0x00080000,
/** Indicates this class must be DLL exported/imported (along with all of it's members) */
CLASS_RequiredAPI = 0x00100000,
/** Indicates that references to this class default to instanced. Used to be subclasses of UComponent, but now can be any UObject */
CLASS_DefaultToInstanced = 0x00200000,
/** Indicates that the parent token stream has been merged with ours. */
CLASS_TokenStreamAssembled = 0x00400000,
/** Class has component properties. */
CLASS_HasInstancedReference= 0x00800000,
/** Don't show this class in the editor class browser or edit inline new menus. */
CLASS_Hidden = 0x01000000,
/** Don't save objects of this class when serializing */
CLASS_Deprecated = 0x02000000,
/** Class not shown in editor drop down for class selection */
CLASS_HideDropDown = 0x04000000,
/** Class settings are saved to <AppData>/..../Blah.ini (as opposed to CLASS_DefaultConfig) */
CLASS_GlobalUserConfig = 0x08000000,
/** Class was declared directly in C++ and has no boilerplate generated by UnrealHeaderTool */
CLASS_Intrinsic = 0x10000000,
/** Class has already been constructed (maybe in a previous DLL version before hot-reload). */
CLASS_Constructed = 0x20000000,
/** Indicates that object configuration will not check against ini base/defaults when serialized */
CLASS_ConfigDoNotCheckDefaults = 0x40000000,
/** Class has been consigned to oblivion as part of a blueprint recompile, and a newer version currently exists. */
CLASS_NewerVersionExists = 0x80000000,
//@}
/** @name Flags to inherit from base class */
//@{
CLASS_Inherit = CLASS_Transient | CLASS_DefaultConfig | CLASS_Config | CLASS_PerObjectConfig | CLASS_ConfigDoNotCheckDefaults | CLASS_NotPlaceable
| CLASS_PointersDefaultToAutoWeak | CLASS_PointersDefaultToWeak | CLASS_Const
| CLASS_HasInstancedReference | CLASS_Deprecated | CLASS_DefaultToInstanced | CLASS_GlobalUserConfig,
/** these flags will be cleared by the compiler when the class is parsed during script compilation */
CLASS_RecompilerClear = CLASS_Inherit | CLASS_Abstract | CLASS_NoExport | CLASS_Native | CLASS_Intrinsic | CLASS_TokenStreamAssembled,
/** these flags will be cleared by the compiler when the class is parsed during script compilation */
CLASS_ShouldNeverBeLoaded = CLASS_Native | CLASS_Intrinsic | CLASS_TokenStreamAssembled,
/** these flags will be inherited from the base class only for non-intrinsic classes */
CLASS_ScriptInherit = CLASS_Inherit | CLASS_EditInlineNew | CLASS_CollapseCategories,
//@}
/** This is used as a mask for the flags put into generated code for "compiled in" classes. */
CLASS_SaveInCompiledInClasses =
CLASS_Abstract |
CLASS_DefaultConfig |
CLASS_GlobalUserConfig |
CLASS_Config |
CLASS_Transient |
CLASS_Native |
CLASS_NotPlaceable |
CLASS_PerObjectConfig |
CLASS_ConfigDoNotCheckDefaults |
CLASS_PointersDefaultToWeak |
CLASS_EditInlineNew |
CLASS_CollapseCategories |
CLASS_Interface |
CLASS_PointersDefaultToAutoWeak |
CLASS_DefaultToInstanced |
CLASS_HasInstancedReference |
CLASS_Hidden |
CLASS_Deprecated |
CLASS_HideDropDown |
CLASS_Intrinsic |
CLASS_AdvancedDisplay |
CLASS_Const |
CLASS_MinimalAPI |
CLASS_RequiredAPI,
CLASS_AllFlags = 0xFFFFFFFF,
};
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
for(TObjectIterator<UClass> ClassIter; ClassIter; ++ClassIter)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Yellow, ClassIter->GetName());
}
获取所有的类
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
UFunction *PixelStr = BlurCharacterClass->FindFunctionByName("GetMousePixel");
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Yellow, PixelStr->GetName());
通过方法名字查找到方法
ABlurCharacter *BlurCharacter = NewObject<ABlurCharacter>();
UClass *BlurCharacterClass = BlurCharacter->GetClass();
UFunction *PixelMethod = BlurCharacterClass->FindFunctionByName("GainMousePixel", EIncludeSuperFlag::ExcludeSuper);
if(PixelMethod->IsValidLowLevel())
{
//分配空间并初始化为0
uint8* LocSize = static_cast<uint8*>(FMemory_Alloca(PixelMethod->ParmsSize));//获取参数所占的空间大小来进行一个空间分配
FMemory::Memzero(LocSize, PixelMethod->ParmsSize);
//给方法内参数赋值
for(TFieldIterator<UProperty> Pro(PixelMethod); Pro; ++Pro)
{
if(Pro->GetName() == FString("num"))
{
*Pro->ContainerPtrToValuePtr<FString>(LocSize) = "5";
}
}
//使用ProcessEvent调用方法
BlurCharacter->ProcessEvent(PixelMethod, LocSize);
}
void ABlurCharacter::GainMousePixel(FString num)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Green, num);
}
使用ProcessEvent调用函数
AMyProjectPawn* MyProjectPawn = NewObject<AMyProjectPawn>();
UClass* BlurCharacterClass = MyProjectPawn->GetClass();
UFunction* PixelMethod = BlurCharacterClass->FindFunctionByName("GainMousePixel", EIncludeSuperFlag::ExcludeSuper);
if (PixelMethod->IsValidLowLevel()) {
uint8* AllFuncParam = static_cast<uint8*>(FMemory_Alloca(PixelMethod->ParmsSize));
FMemory::Memzero(AllFuncParam, PixelMethod->ParmsSize);
FFrame Frame(nullptr, PixelMethod, &AllFuncParam);
PixelMethod->Invoke(MyProjectPawn, Frame, &AllFuncParam + PixelMethod->ReturnValueOffset);
}
void AMyProjectPawn::GainMousePixel(FString num)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Green, TEXT("VALUE = ") + num);
}
使用Invoke调用函数
反射数据的基类:
class COREUOBJECT_API UField : public UObject
{
DECLARE_CASTED_CLASS_INTRINSIC(UField, UObject, CLASS_Abstract, TEXT("/Script/CoreUObject"), CASTCLASS_UField)
}