On an old post (C++ Introspection and ContainerPtrToValuePtr). I’ve done a full introspection of an actor class, diging in arrays and structs to access basic properties.
Now I need to extend this introspection to go though components (ie. FObjectProperty). I’ve updated the code as following but I’ve probably missed something around pointers to get access to values inside a FObjectProperty.
Something is probably wrong below COMMENT1 and COMMENT2.
void AUnrSimulationActor::Dump() const
{
for (TFieldIterator<FProperty> vPropIt(GetClass(), EFieldIterationFlags::IncludeSuper); vPropIt; ++vPropIt)
{
auto vProperty = *vPropIt;
DumpAnyProperty(vProperty, this, GetName());
}
}
void AUnrSimulationActor::DumpAnyProperty(const FProperty* aProperty, const void* aContainerPtr, const FString& aRelativePath, bool aAddPropertyNameToPath) const
{
if (const FArrayProperty* vArrayProperty = CastField<const FArrayProperty>(aProperty))
{
auto vArrayName = vArrayProperty->GetAuthoredName();
auto vArrayPtr = vArrayProperty->ContainerPtrToValuePtr<void>(aContainerPtr);
FScriptArrayHelper vArrayHelper(vArrayProperty, vArrayPtr);
auto vCount = vArrayHelper.Num();
for (int vIndex = 0; vIndex < vCount; vIndex++)
{
auto vItemPath = aRelativePath + "." + vArrayName + "[" + FString::FromInt(vIndex) + "]";
auto vArrayItemPtr = vArrayHelper.GetRawPtr(vIndex);
DumpAnyProperty(vArrayProperty->Inner, vArrayItemPtr, vItemPath, false);
}
}
else if (const FStructProperty* vStructProperty = CastField<const FStructProperty>(aProperty))
{
auto vStructPropertyName = vStructProperty->GetAuthoredName();
auto vStructName = vStructProperty->Struct->GetName();
auto vStructPath = aAddPropertyNameToPath ? aRelativePath + "." + vStructPropertyName : aRelativePath;
UE_LOG(LogTemp, Display, TEXT("%s (%s)"), *vStructPath, *vStructName);
DumpStructProperty(vStructProperty, aContainerPtr, vStructPath);
}
// COMMENT1
else if (const FObjectProperty* vObjectProperty = CastField<const FObjectProperty>(aProperty))
{
auto vObjectPropertyName = vObjectProperty->GetAuthoredName();
auto vObjectPath = aAddPropertyNameToPath ? aRelativePath + "." + vObjectPropertyName : aRelativePath;
DumpObjectProperty(vObjectProperty, aContainerPtr, vObjectPath);
}
else
{
DumpBasicProperty(aProperty, aContainerPtr, aRelativePath);
}
}
// COMMENT2
void AUnrSimulationActor::DumpObjectProperty(const FObjectProperty* aObjectProperty, const void* aContainerPtr, const FString& aRelativePath) const
{
// ERROR MAY BE BELOW !!
auto vObjectPtr = aObjectProperty->ContainerPtrToValuePtr<void>(aContainerPtr);
for (TFieldIterator<FProperty> vPropIt(aObjectProperty->PropertyClass, EFieldIterationFlags::IncludeSuper); vPropIt; ++vPropIt)
{
auto vProperty = *vPropIt;
DumpAnyProperty(vProperty, vObjectPtr, aRelativePath);
}
}
void AUnrSimulationActor::DumpStructProperty(const FStructProperty* aStructProperty, const void* aContainerPtr, const FString& aRelativePath) const
{
auto vStructPtr = aStructProperty->ContainerPtrToValuePtr<void>(aContainerPtr);
for (TFieldIterator<FProperty> vPropIt(aStructProperty->Struct, EFieldIterationFlags::IncludeSuper); vPropIt; ++vPropIt)
{
auto vProperty = *vPropIt;
DumpAnyProperty(vProperty, vStructPtr, aRelativePath);
}
}
void AUnrSimulationActor::DumpBasicProperty(const FProperty* aProperty, const void* aContainerPtr, const FString& aRelativePath) const
{
auto vPropertyPath = aRelativePath + "." + aProperty->GetAuthoredName();
FString vIsNative = aProperty->IsNative() ? TEXT("CPP") : TEXT("BP");
FString vValue = "Unknown";
if (aProperty->GetClass() == FIntProperty::StaticClass())
{
auto vValuePtr = aProperty->ContainerPtrToValuePtr<int>(aContainerPtr);
vValue = FString::FromInt(*vValuePtr);
}
else if (aProperty->GetClass() == FDoubleProperty::StaticClass())
{
auto vValuePtr = aProperty->ContainerPtrToValuePtr<double>(aContainerPtr);
vValue = FString::SanitizeFloat(*vValuePtr);
}
else if (aProperty->GetClass() == FStrProperty::StaticClass())
{
auto vValuePtr = aProperty->ContainerPtrToValuePtr<FString>(aContainerPtr);
vValue = *vValuePtr;
}
else if (aProperty->GetClass() == FBoolProperty::StaticClass())
{
auto vValuePtr = aProperty->ContainerPtrToValuePtr<bool>(aContainerPtr);
vValue = *vValuePtr ? "true" : "false";
}
UE_LOG(LogTemp, Display, TEXT("%s %s %s"), *vPropertyPath, *vIsNative, *vValue);
}