Got this on my todo list for my current project and the model I'm thinking about looks something like this:
player_a is on frame 400 locally.
the server is processing player_a's frame 395
player_a is replaying player_b's frame 392
player_b is on frame 402 locally
the server is processing player_b's frame 395
player_b is replaying player_a's frame 393
player_a shoots at player_b and its input, rotation, etc are passed to the server as part of his frame 400 data along with information about its assumption that it got a hit-confirm against player_b @ 392
When the server comes to process this frame it checks the hit against a simulation of player_a@400 against player_b@392 and if it scores the hit it corrects player_b with the hit if it misses it corrects player_a with a negation of the hit. This comparing hit's at different frames removes the need to lead targets, etc.
I guess that raises questions like:
- How far in the past is still "legit" (should player_a's lag give it a larger window to hit player_b and how goofy will it look if player_a shoots player_b half a second after it walks past player_b and round a corner)
- If player_b activates a shield at frame 398 should it's negation at what is "before" from the servers perspective but "after" from player_a's perspective block player_a's shot at frame 400?
This is a great video on the subject:
And from what they talk about in that video my (naive) understanding is it works like the above and recent tweaks, talked about @9:42 (exceptions to "favour the shooter") mean in the example where player_b pops a shield that the shield will mitigate even if the hit-test is in the past(in Overwatch's case the server must have already processed the shield activation, meaning lag will hurt your mitigation perhaps?).
I've yet to do this on my own project so this is all speculative, and would also love to hear from someone in the know :)