Private Properties in AActor causing headaches with Custom Replication!

I ran into this same problem today. Here’s how I solved it (admittedly using a bit of a hack, but nothing too extreme).

First note how DOREPLIFETIME is defined:



#define DOREPLIFETIME_WITH_PARAMS(c,v,params) \
{ \
   FProperty* ReplicatedProperty = GetReplicatedProperty(StaticClass(), c::StaticClass(),GET_MEMBER_NAME_CHECKED(c,v)); \
   RegisterReplicatedLifetimeProperty(ReplicatedProperty, OutLifetimeProps, params); \
}

#define DOREPLIFETIME(c,v) DOREPLIFETIME_WITH_PARAMS(c,v,FDoRepLifetimeParams())


DOREPLIFETIME_CONDITION, DOREPLIFETIME_CONDITION_NOTIFY etc. are similar. They all go to DOREPLIFETIME_WITH_PARAMS. The culprit here is GET_MEMBER_NAME_CHECKED, which was written with good intentions - but has the unfortunate side effect of disallowing access to private and protected members:



// Returns FName(TEXT("MemberName")), while statically verifying that the member exists in ClassName
#define GET_MEMBER_NAME_CHECKED(ClassName, MemberName) \
   ((void)sizeof(UE4Asserts_Private::GetMemberNameCheckedJunk(((ClassName*)0)->MemberName)), FName(TEXT(#MemberName)))


Fortunately, the only thing this macro really does is convert the member name to an FName. My solution therefore was to replace this chain of macros, placing the following in my common header:



#define GET_MEMBER_NAME_UNCHECKED(ClassName, MemberName) \
   FName(TEXT(#MemberName))

#define DOREPLIFETIME_WITH_PARAMS_UNCHECKED(c,v,params) \
{ \
   FProperty* ReplicatedProperty = GetReplicatedProperty(StaticClass(), c::StaticClass(),GET_MEMBER_NAME_UNCHECKED(c,v)); \
   RegisterReplicatedLifetimeProperty(ReplicatedProperty, OutLifetimeProps, params); \
}

#define DOREPLIFETIME_UNCHECKED(c,v) DOREPLIFETIME_WITH_PARAMS_UNCHECKED(c,v,FDoRepLifetimeParams())


The ‘_UNCHECKED’ suffix indicates that the member access is, well, unchecked. This way you can use the ‘_UNCHECKED’ macros where needed (which shouldn’t be very often) and continue to use the regular macros elsewhere. Final usage:



void MyActor::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
   // Not calling Super::GetLifetimeReplicatedProps()
   // ...but we still want to replicate private variable bCanBeDamaged
   DOREPLIFETIME_UNCHECKED(AActor, bCanBeDamaged);
}


1 Like