With a Fixed ticking policy in NPP, the server frame is synced so that we can ensure damage is applied on the same frame on both the server and the predicted client. However, this thread mentions that with an Independent ticking policy the frame number is not synced (and neither is the total simulation time). [Content removed]
This makes it difficult to execute certain actions without instantly triggering a reconcile. In my immediate example, I’d like to apply client-auth damage to another players pawn. Applying this in the local simulation and then sending a reliable RPC to instantly apply it on the server is never going to line up. I’m also no longer able to calculate if it hit on the server (which means I cannot rely on SimulationTick on the server to apply the hit) as all simulations are ticking in their own timeline on the client so the view is not the same. How should I handle this situation?
With independent ticking, the owning client is driving the simulation time for the server, similar to how the character movement component handles its timing. Because of this, clients can forward predict their own character, but forward predicting other clients’ characters will generally result in corrections, since those clients will have different simulation times and update cadences.
In the example here, it does seem as though one of the clients involved will have to have a correction applied. Even if the client applying the damage can forward predict it locally without corrections, the client receiving the damage may also be moving independently, causing a correction there when it receives the damage event from the server.
That being said, we do recommend thinking of corrections as being expected and unavoidable, with the focus on making corrections less noticeable rather than on avoiding them entirely. We also do generally recommend against giving clients authority over events that affect other players, as these should generally be handled by the server. For instance, in a situation like this the client applying the damage may predictively display just the cosmetic effects of the damage event, while the server handles the gameplay effects.
Hi Kieran - Independent ticking mode currently doesn’t do anything to respect the Sim Proxy “Forward Predict” vs “Interpolated” setting. It’s always just interpolating towards the latest received frame. There’s nothing inherently incompatible with the concepts of Independent ticking and Forward Prediction of sim proxies, it would just need to be implemented. The main problem is resolving predicted frames that would be generated at the client’s rate vs authoritative frames coming from the server, but it seems solvable.
In your original question, are you talking about some kind of hitscan weapon where the attacking client is authoritative over whether an attack lands another character? Would adding some attack information to the attacking client’s inputCmd help here?
I don’t see any way around having to handle at least 1 correction on the attacker’s machine that blows away your locally-predicted damage of the target character.
At the same time you’ve written the target character’s sync state (on the attacker’s machine), there is already a new sync state for the target character in flight from the server to the attacker’s machine. The attacker’s machine hasn’t even sent the inputs that include your damage-causing event yet.
By directly writing to the target character’s sync state on the attacker’s machine, there becomes a mix of predicted data with historical authoritative sync state data that you’ve already received from the server.
Is there a scheme you could use where the predicted event causes a temporary local change that will expire after a certain amount of time? (i.e. if the server doesn’t reflect the change) And visually, you treat predicted vs confirmed changes differently? Like showing the healthbar section about to be dropped based on the predicted change, but only actually dropping it based on the server-authoritative state?
I think what I’m looking for here is to apply the damage on the server at the time frame of the other character, rather than trying to apply it on the same frame as the local character. I haven’t tested this yet though.
Corrections being applied is fine in this case. The important thing is to see a response damage number when the target is hit and in 99% of cases to not see the correction pulling the health back up before it goes down again. It’s not necessarily an authoritative damage application, it’s just to remove the delay from the impact for something that will definitely be applied assuming the target still has enough health when the packet arrives.
I’ve investigated this a little more and where a fixed simulation would trigger a reconcile after applying the predicted damage value, the independent simulation seems to just write over the value every frame even if NetworkLODs are set to ForwardPredict on the simulation.
To add to this, in Fixed mode I can receive a SimulationTick on simulated proxies if I set the model def capabilities to ForwardPredict. This doesn’t exist in Independent. Should it exist? It feels as if predicting a simulation that isn’t owned is maybe not supported at all in Independent mode?
I think I’m missing a fundamental understanding of Independent mode compared to Fixed mode so any pointers to help with applying this damage predictively and then overriding the predicted damage value with the authoritative value when it arrives would be appreciated!
Yep, that’s right. I really just want the client to say that it has hit a target with X damage and then the server to apply that when it receives it.
I’ve tried pushing this through the inputCmd of the attacking character and then applying it directly to the simulation with NetworkPredictionProxy.WriteSyncState (as the health value is in a different NetworkPredictionComponent). However, I’m still seeing the issue of the first frame the damage is getting applied correctly on the predicted client and then it snaps back instantly until the replicated health value changes. It feels like I’d need to apply it every frame until that value changes but I’m not sure how to get that frame that it needs to be applied until. I’m assuming it maybe ties into FVariableTickState::FInterpolationState but maybe I’m looking at it the wrong way?
That probably does sound like the best solution! I’ll just have to find a notification when the damage has been authoritatively applied so that I can remove the predicted amount. Maybe cues can help with this.