x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Serious issue with RepNotify and Struct UPROPERTY's

Have sought out Epic support on this issue, but am reposting here to make users aware of the bug and workaround for now.

I've found what I believe to be a severe bug with RepNotify functions when used with struct UPROPERTY's, when specifying the optional 'Previous' value parameter. The parameter provided to "Previous Value" is always out-of-date. This is 100% reproducible and I'm surprised this hasn't been picked up before.

Given the following USTRUCT():

 USTRUCT()
 struct FRepAbilityState
 {
     GENERATED_BODY()
 public:
     void MarkActive(const float ServerWorldTime)
     {
         UE_LOG(LogAbility, Log, TEXT("MARKED ACTIVE"));
 
         ActivateCounter++;
         LastActivationTime = ServerWorldTime;
     }
 
     void MarkInactive()
     {
         UE_LOG(LogAbility, Log, TEXT("MARKED INACTIVE"));
 
         DeactivateCounter++;
     }
 
     FRepAbilityState()
         : ActivateCounter(0)
         , DeactivateCounter(0)
         , LastActivationTime(0.f)
     {}
 
 protected:
     UPROPERTY() uint8 ActivateCounter;
     UPROPERTY() uint8 DeactivateCounter;
     UPROPERTY() float LastActivationTime;
 };

And a member variable of this struct in an Actor class, with the following RepNotify function:

 UCLASS()
 class ASomeActor : public AActor
 {
     GENERATED_BODY()
 protected:
     UPROPERTY(ReplicatedUsing = "OnRep_ActivationState")
     FRepAbilityState ActivationState;
 
     UFUNCTION()
     void OnRep_ActivationState(const FRepAbilityState& OldValue)
     {
         UE_LOG(LogAbility, Log, TEXT("Current - %s"), *ActivationState.ToString());
         UE_LOG(LogAbility, Log, TEXT("Previous - %s"), *OldValue.ToString());
     }
 };

'OldValue' is always out of date when the Server calls 'MarkActive()', then 'MarkInactive()'. This occurs whether they are called in the same frame, or after significant time between the calls. The output from visual studio yields the following results:

 Server: MARKED ACTIVE
 Client: Current - Activation: 1 --- Deactivation: 0 --- Time: 9.32
 Client: Previous - Activation: 0 --- Deactivation: 0 --- Time: 0.00
 
 Server: MARKED INACTIVE
 Client: Current - Activation: 1 --- Deactivation: 1 --- Time: 9.32
 Client: Previous - Activation: 0 --- Deactivation: 0 --- Time: 0.00

This is clearly incorrect. The second Client: Previous entry should have an activation value of 1, and a time of 9.32.

If however, I provide a manual implementation of NetSerialize() for the struct. which mimics what the serializer does anyway:

 template<>
 struct TStructOpsTypeTraits<FRepAbilityState> : public TStructOpsTypeTraitsBase2<FRepAbilityState>
 {
     enum
     {
         WithNetSerializer = true,
     };
 };
 
 bool FRepAbilityState::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
 {
     Ar << LastActivationTime;
     Ar << ActivateCounter;
     Ar << DeactivateCounter;
 
     bOutSuccess = true;
     return true;
 }

The RepNotify is called with the correct OldValue, as shown again by the log. Note that the only difference here is the manual inclusion of the NetSerialize() function - but the log now shows the correct (expected) output:

 Server: MARKED ACTIVE
 Client: Current - Activation: 1 --- Deactivation: 0 --- Time: 8.46
 Client: Previous - Activation: 0 --- Deactivation: 0 --- Time: 0.00
 Server: MARKED INACTIVE
 Client: Current - Activation: 1 --- Deactivation: 1 --- Time: 8.46
 Client: Previous - Activation: 1 --- Deactivation: 0 --- Time: 8.46

I've done some digging and found a (very old and unanswered) answerhub post which alludes to the same behaviour, indicating that the shadow data stored by the replicator is out-of-date when only single properties of the struct are modified. I'm surprised this hasn't been noticed and fixed already as it is quite a severe issue - but perhaps it's only noticeable when monitoring changes more closely.

https://answers.unrealengine.com/questions/303504/repnotify-shadow-data-is-stale-when-single-propert.html

Product Version: UE 4.20
Tags:
more ▼

asked Dec 17 '18 at 05:43 PM in C++ Programming

avatar image

TheJamsh
775 53 81 131

(comments are locked)
10|2000 characters needed characters left

0 answers: sort voted first
Be the first one to answer this question
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question