maxnt
Topic Author
Posts: 1
Joined: 28 Jun 2021, 11:18

UE4 UObject to Noesis Derrived Object Reflective copy

20 Sep 2021, 13:56

Thought I would drop this post to share a little knowledge that I thought might be useful to others.
A big shout out to Sergio from the Noesis team for helping me!

In UE4 using Noesis, this is my reflection approach for copying UProperties values from a bound UObject within the DataContext to a derived BaseComponent data object.

I did this so that my game code didn't have to know about complex component types within my custom Noesis component. Values would be copied across on DependencyProperty PropertyChanged callback by simply having matching property names.
	class UObjectToNsReflection
	{
	public:	

		static void CopyProperties(Noesis::Ptr<Noesis::BaseComponent> FromObject, Noesis::Ptr<Noesis::BaseComponent> TargetObject)
		{
			if (FromObject && TargetObject)
			{
				UObject* UObj = NoesisCreateUObjectForComponent(FromObject);
				const Noesis::TypeClass* TypeClass = TargetObject->GetClassType();

				if (UObj && TypeClass)
				{
					//UE4 Reflection to copy properties across
					for (TFieldIterator<FProperty> It(UObj->GetClass()); It; ++It)
					{
						FProperty* Property = *It;
						Noesis::String NsSymbolString = TCHARToNsString(*Property->GetNameCPP());
						Noesis::Symbol Symb = Noesis::Symbol(NsSymbolString.Str());

						Noesis::TypeClassProperty FindPropertyResult = Noesis::FindProperty(TypeClass, Symb);
						if (FindPropertyResult.property != nullptr)
						{
							Noesis::Ptr<Noesis::BaseComponent> BoxedValue;
							if (FBoolProperty* BoolPropertyPtr = CastField<FBoolProperty>(Property))
							{
								BoxedValue = Noesis::Boxing::Box(*BoolPropertyPtr->ContainerPtrToValuePtr<bool>(UObj));
							}
							else if (FStrProperty* StrPropertyPtr = CastField<FStrProperty>(Property))
							{
								FString* StrVal = StrPropertyPtr->ContainerPtrToValuePtr<FString>(UObj);
								BoxedValue = Noesis::Boxing::Box(TCHARToNsString(**StrVal));
							}
							else if (FIntProperty* IntPropertyPtr = CastField<FIntProperty>(Property))
							{
								BoxedValue = Noesis::Boxing::Box(IntPropertyPtr->ContainerPtrToValuePtr<int>(UObj));
							}
							else if (FStructProperty* StructPropertyPtr = CastField<FStructProperty>(Property))
							{
								if (StructPropertyPtr->Struct->GetName() == TEXT("Timespan"))
								{
									FTimespan* Ts = It->ContainerPtrToValuePtr<FTimespan>(UObj);
									BoxedValue = Noesis::Boxing::Box(Noesis::TimeSpan(Ts->GetTicks()));
									
									// .. More UE4 FStruct types
								}
							}

							// Set property using boxed value
							FindPropertyResult.property->SetComponent(TargetObject.GetPtr(), BoxedValue);
						}
					}
				}
			}
		}
	};

Who is online

Users browsing this forum: Google [Bot] and 84 guests