输出UE当前所有UObject的基础信息
目标
之前尝试制作过一个观察UObject的工具,但是那个工具的封装有些冗余了。。
本篇将写个函数直接输出所有UObject的所有基础信息。
Uobject基础信息
Uobject
的继承关系如下:
UObject
类和UObjectBaseUtility
类都没有定义新的字段。基础信息都在UObjectBase
中定义,共有五个:
/** Flags used to track and report various object states. This needs to be 8 byte aligned on 32-bit
platforms to reduce memory waste */
EObjectFlags ObjectFlags;
/** Index into GObjectArray...very private. */
int32 InternalIndex;
/** Class the object belongs to. */
UClass* ClassPrivate;
/** Name of this object */
FName NamePrivate;
/** Object this object resides in. */
UObject* OuterPrivate;
也有对应public函数可以访问:
/**
* Returns the unique ID of the object...these are reused so it is only unique while the object is alive.
* Useful as a tag.
**/
FORCEINLINE uint32 GetUniqueID() const
{
return (uint32)InternalIndex;
}
/** Returns the UClass that defines the fields of this object */
FORCEINLINE UClass* GetClass() const
{
return ClassPrivate;
}
/** Returns the UObject this object resides in */
FORCEINLINE UObject* GetOuter() const
{
return OuterPrivate;
}
/** Returns the logical name of this object */
FORCEINLINE FName GetFName() const
{
return NamePrivate;
}
/**
* Retrieve the object flags directly
*
* @return Flags for this object
**/
FORCEINLINE EObjectFlags GetFlags() const
{
checkfSlow((ObjectFlags & ~RF_AllFlags) == 0, TEXT("%s flagged as RF_AllFlags"), *GetFName().ToString());
return ObjectFlags;
}
这五个信息也是本篇想输出出来的内容
写一个函数输出UE当前所有UObject的基础信息
对于这五个信息:
- InternalIndex 很直白,就输出编号就行了。
- NamePrivate 是这个Object的名字,也是直接输出。
- ClassPrivate 说明了这个Object的类,而 “类”——
UClass
,也是一种Object,所以也可以直接输出它的名字。 - OuterPrivate 是这个Object的Outer。需要注意的是,Outer之外可能还有Outer,所以需要递归的方式来输出。
- ObjectFlags 是这个Object的Flag。它的每一位都是一个标志,可以使用
&
符号来查询是否存在这个标志。(由于它所属的枚举类并非是UENUM
,没有反射信息,所以我只能逐个手写出每个标志对应的字符串了)
最后完整的函数如下:
DEFINE_LOG_CATEGORY_STATIC(LogYKS, Log, All);
FString RecursiveGetOuterText(UObject* Object, FString Result)
{
if (!Object->GetOuter())
return Result;
else
{
Result += "->(" + Object->GetOuter()->GetFName().ToString() + ")";
return RecursiveGetOuterText(Object->GetOuter(), Result);
}
}
FString GetFlagText(EObjectFlags Flag)
{
FString Result;
if (Flag & RF_NoFlags)
Result += "+RF_NoFlags";
if (Flag & RF_Public)
Result += "+RF_Public";
if (Flag & RF_Standalone)
Result += "+RF_Standalone";
if (Flag & RF_MarkAsNative)
Result += "+RF_MarkAsNative";
if (Flag & RF_Transactional)
Result += "+RF_Transactional";
if (Flag & RF_ClassDefaultObject)
Result += "+RF_ClassDefaultObject";
if (Flag & RF_ArchetypeObject)
Result += "+RF_ArchetypeObject";
if (Flag & RF_Transient)
Result += "+RF_Transient";
if (Flag & RF_MarkAsRootSet)
Result += "+RF_MarkAsRootSet";
if (Flag & RF_TagGarbageTemp)
Result += "+RF_TagGarbageTemp";
if (Flag & RF_NeedInitialization)
Result += "+RF_NeedInitialization";
if (Flag & RF_NeedLoad)
Result += "+RF_NeedLoad";
if (Flag & RF_KeepForCooker)
Result += "+RF_KeepForCooker";
if (Flag & RF_NeedPostLoad)
Result += "+RF_NeedPostLoad";
if (Flag & RF_NeedPostLoadSubobjects)
Result += "+RF_NeedPostLoadSubobjects";
if (Flag & RF_NewerVersionExists)
Result += "+RF_NewerVersionExists";
if (Flag & RF_BeginDestroyed)
Result += "+RF_BeginDestroyed";
if (Flag & RF_FinishDestroyed)
Result += "+RF_FinishDestroyed";
if (Flag & RF_BeingRegenerated)
Result += "+RF_BeingRegenerated";
if (Flag & RF_DefaultSubObject)
Result += "+RF_DefaultSubObject";
if (Flag & RF_WasLoaded)
Result += "+RF_WasLoaded";
if (Flag & RF_TextExportTransient)
Result += "+RF_TextExportTransient";
if (Flag & RF_LoadCompleted)
Result += "+RF_LoadCompleted";
if (Flag & RF_InheritableComponentTemplate)
Result += "+RF_InheritableComponentTemplate";
if (Flag & RF_DuplicateTransient)
Result += "+RF_DuplicateTransient";
if (Flag & RF_StrongRefOnFrame)
Result += "+RF_StrongRefOnFrame";
if (Flag & RF_NonPIEDuplicateTransient)
Result += "+RF_NonPIEDuplicateTransient";
if (Flag & RF_Dynamic)
Result += "+RF_Dynamic";
if (Flag & RF_WillBeLoaded)
Result += "+RF_WillBeLoaded";
if (Flag & RF_HasExternalPackage)
Result += "+RF_HasExternalPackage";
return Result;
}
void PrintAllUObjectInfo()
{
for (int i = 0; i < GUObjectArray.GetObjectArrayNum(); i++)
{
FUObjectItem* ObjectElement = GUObjectArray.IndexToObject(i);
if (ObjectElement->Object)
{
UObject* Object = (UObject*)ObjectElement->Object;
UE_LOG(LogYKS, Warning, TEXT("[%d], <%s>, %s, %s, %s")
, Object->GetUniqueID() //InternalIndex
, *(Object->GetClass()->GetFName().ToString()) //类
, *(Object->GetFName().ToString()) //名字
, *RecursiveGetOuterText(Object, "") //Outer链
, *GetFlagText(Object->GetFlags()) //具有的Flag
);
}
}
}
结果
在UE中调用上面的PrintAllUObjectInfo()
函数后,将会看到信息被输出出来:
还可以将信息复制出来,保存为.csv
文件,由于上面输出时已经加了,
,所以可以被识别为表格。(可以顺带将LogYKS: Warning:
替换为空以去掉多余信息)
保存的.csv
文件可以使用Excel打开,这样有排版后更容易浏览: