Associated UDN [Link Removed]


We've been having some issues with the replication of attributes. Namely we have an OnRep_ function for an attribute that receives FGameplayAttributeData& OldValue and passes that to GAMEPLAYATTRIBUTE_REPNOTIFY. Note that by the time this is hit the attribute already has its current value set from replication.

This call forwards all of this to SetBaseAttributeValueFromReplication which in turn calls OnAttributeAggregatorDirty which then calls InternalUpdateNumericalAttribute. In here however it is assumed that the current value is the old value (float OldValue = Owner->GetNumericAttribute(Attribute)) and the new value is passed in via function parameter. This is true for the server but in case of the client these 2 are the same because as mentioned by the time the repnotify macro is called, replication has already set the attribute to the current value and thus the old value is lost by the time InternalUpdateNumericalAttribute is called.


This results in both NewValue and OldValue being identical on the client by the time the aggregator delegates are called and our "if newvalue != oldvalue" check fails.


Steps to Reproduce

This is super hard to reproduce without writing custom code.  Basically you need to hook into the Attribute Change callbacks to verify the old/new values are correct.

A better way to help verify this:

Go into Apollo_FiringRange.  Change the Health Debuf pick-up GameplayEffect to debuf your CurrentShield to 0.9x.  Then duplicate it (so you can stack that effect).  Turn on logging of the AbilitySystem:  "Log LogAbilitySystem Log".  Then play the game and double-debuf your shield, then go to the Health Pickups section and pick-up a Shield replenishing item.  When you drink it, you should get some logs and you're looking for:


            ABILITY_LOG(Log, TEXT("SetBaseAttributeValueFromReplication [%s]: %s rewound to state NewBaseValue: %.2f  OldCurrentValue: %.2f"), OwnerIsNetAuthority ? TEXT("Authority") : TEXT("Client"), *Attribute.AttributeName, ServerBaseValue, OldEvaluatedValue);


That coupled with everything that follows it.  You should see that your shield value ends up being correct (e.g. the client/server agree and that the rewinding of those values was to a base value, and that the final change was from 0 to whatever your shield value now is).

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-137205 in the post.

Login to Vote

ComponentUE - Gameplay
Affects Versions4.27.1
Target Fix5.3
Fix Commit24472744
Main Commit24473729
CreatedDec 10, 2021
ResolvedMar 6, 2023
UpdatedApr 29, 2023