I’m writing code that uses reflection to iterate through the properties of a UClass, and then certain of those properties will have their values set to values stored in external data.
I currently have a utility function where this happens, it gets a couple of parameters:
UObject* ObjectToFill, FProperty* PropertyToSet
Dont worry about the value to set, just assume we have it
(it could be various datatypes, but for the purposes of this, assume some flavor of int which can be cast as low as it needs to for an enum)
What I’m currently doing for an int32:
FIntProperty* PropInt32 = CastField(PropertyToSet);
if (int32* ValuePtr = PropInt32->ContainerPtrToValuePtr(ObjectToFill))
*ValuePtr = (int32)Value.IntVal;
This is all well and good, because we are dealing with an integral datatype and not (I assume) a UEnum.
So I’m wondering if I can do something like:
FEnumProperty* PropEnum_2 = CastField(PropertyToSet);
if (UEnum* ValuePtr = PropEnum_2->ContainerPtrToValuePtr(ObjectToFill))
But even if I can (because im not sure a UEnum would be a ‘value’ in this case (as its another reflection type itself), if it did work, I wouldn’t actually know what to do with a UEnum -
It has a bunch of methods for finding out about the enumeration itself, but none that I can see for setting the value of an instance of one.
Can anyone steer me in the right direction please?
Wouldn’t ContainerPtrToValuePtr return an EWhatever? and not the UEnum?
In the integer case it returns a pointer to the actual property type (int) and not the reflection type.
Ultimately I think you could make some assumptions and treat any enumeration property as a uint8 since UHT forces you to declare enums as “enum class EWhatever : uint8” if you want to use them as a UPROPERTY.
You are right actually with your first comment.
I fell foul here of basically trying to code to the values of EClassCastFlags without actually reading what they represented.
I had written a switch/case on that, and included all the possible values, and then worked over most of them removing the values that I obviously would never encounter in my case and letting them fall into the default: case.
What had confused me at the time was CASTCLASS_UEnum vs CASTCLASS_FEnumProperty
I thought I was going to need to handle the UEnum and didn’t realise they would (obviously) be FEnumProperty, which I had already coded for much as you mentioned.
If I had only changed my test case to include an enum, I would have seen that it was already working - but I didn’t because I thought it would automatically fail.
The code I ended up using is pretty much the same as the other cases:
case CASTCLASS_FEnumProperty:
{
FEnumProperty* PropEnum_2 = CastField<FEnumProperty>(PropertyToSet);
if (uint8* ValuePtr = PropEnum_2->ContainerPtrToValuePtr<uint8>(ObjectToFill))
*ValuePtr = (uint8)Value.IntVal;
break;
}