I have a case where I want to access the fields of a struct within a class using only the name of the field as an FName. I don’t know the type of struct, but I know it will always be called MyStruct. Target is a UObject*. MyPropName is the name of the property within the struct.
This doesn’t work, I’m including it to explain what I’m trying to achieve. I found this thread which seems to work but it requires that I know the type that MyStruct is.
The situation I have is that I have a kind of Buff system where I give it the name of a property, and the value I want it set to.
The properties that I want to buff are always located inside a member variable called MyStruct, but that struct can be of different types.
I’m approaching it this way because I like encapsulating properties within structs, and I use that to reset variables by keeping a copy of the default MyStruct and on resetting, set MyStruct to the default.
I managed to get stuff working without the MyStruct, where MyPropName was just a float variable on the class itself, but I’d really like to know if it’s possible to access:
MyClass->MyStruct.MyPropName given only FNames and no types for MyStruct.
Your (FProperty* Struct) does not contain MyStruct values, it only contains information about the “MyStruct” property within Target class.
To get a pointer to your struct instance in memory you need to use ContainerPtrToValuePtr.
Then to get information about the properties within MyStruct, you need to access MyStruct reflection data. This is generally done via FMyStruct::StaticStruct or StaticStruct<FMyStruct>, however if you don’t know the type at compile-time you cannot use that here. Also as far as I know there is no GetClass() equivalent for structs.
Fortunately, that information is held in the struct property information, you can access it by casting to FStructProperty.
Here is a working example :
template<typename T>
T* GetPropertyValueWithinStruct(UObject* Target, const FName& StructPropertyName, const FName& PropertyNameWithinStruct)
{
// Get the reflected struct property
FStructProperty* StructProp = (FStructProperty*)Target->GetClass()->FindPropertyByName(StructPropertyName);
// Get a pointer to the struct instance
void* StructPtr = StructProp->ContainerPtrToValuePtr<void>(Target);
// Get the struct reflection data
UScriptStruct* StructReflectionData = StructProp->Struct;
// Get the reflected property within struct
FProperty* PropertyWithinStruct = StructReflectionData->FindPropertyByName(PropertyNameWithinStruct);
// Get value of property within struct
return PropertyWithinStruct->ContainerPtrToValuePtr<T>(StructPtr);
}
Usage (assume MyField is an int32 property in MyStruct) :
Check out ‘Engine\Plugins\VirtualProduction\LevelSnapshots\Source\LevelSnapshots\Private\Selection\PropertySelection.cpp’ at ‘FLevelSnapshotPropertyChain::FindPathToProperty’.
You’ll want to do something like:
FProperty* Struct = Target->GetClass()->FindPropertyByName(FName("MyStruct"));
if (const FStructProperty* StructProperty = CastField<FStructProperty>(Struct))
{
for (TFieldIterator<FProperty> It(StructProperty->Struct); It; ++It)
{
const FProperty* Property = *It;
if (Property.GetFName() == MyPropName)
{
// Here we have the property inside the struct
}
}
}
Then you can do what you were doing before where I assume you were casting single FProperty members to FFloatProperty or something then calling SetPropertyValue. The only difference is that you can’t use UObject as your container void*, you’ll have to use the actual struct void*.
That’s the internal name. Each scriptstruct is basically another UObject and the name you see is not that of the struct, but the object that houses the struct data. If you want the name you wrote for the struct, use GetAuthoredName.