GAS - question about attribute prediction

Hi. I’m learning GAS. My test setup:

  1. TPS default template;
  2. UAbilitySystemComponent is created in Character class;
  3. Attribute set with one test field is also created in Character;
  4. When player press button - Character tries to activate test ability (granted, InstancedPerActor, LocalPredicted);
  5. This ability applies test effect to all other players - just decreases attribute;
  6. I added attribute changed function to print old/new values in real time;
  7. Network emulation is configured to 500ms delay in both directions.

It works fine - Client presses button, ability executes on Client and Server. I see instant attribute value change on client side (prediction) and then Client receives ACK from server. But there is one problem:

  1. Client executes ability and instantly decreases attribute (100.0 - 80.0);
  2. Server do the same on its side (100.0 - 80.0) and replicates actual result to client;
  3. Client receives actual value (80.0). In my opinion, Client should just update attribute value without firing delegate’s event. But I see two event: 80.0 - 100.0 and then 100.0 - 80.0. I visualize value from event in Character’s widget and this 1-frame value change produces glitch in widget.
  4. Situation becomes more interesting with two sequential ability executions: 100.0-80.0 and 80.0-60.0. When Client recevies ACKs from Server - changes may be: 60.0-80.0, 60.0-40.0, 40.0-60.0…
  5. Of course, final attribute’s value will be fully replicated, but due this problem I cannot simply visualize attribute.

Any advices how to work with it? I know that prediction should be used more for Cues and Abilities (right?). But I want to understand this problem at least for learning purpose. Also, there are many things which nice to be predicted in PvE multiplayer (bot health, weapon ammo) and described problem doesn’t allow to do it.

I found this in GameplayPrediction.h:

Problems we attempt to solve:

3. “Redo” How to avoid replaying side effects that we predicted locally but that also get replicated from the server.

Looks like this is my case and it is not solved :(. Any advices? For now I have two ideas:

  1. Simple timer which is started/restarted in attribute event and broadcasts last received value. It works but should be improved.
  2. Maybe some extra value processing? Hold some extra value in Character class and continuously change it toward attribute in Tick function?