1
\$\begingroup\$

This one is a bit complex. So, I'm working on an FPS game that uses deterministic lockstep netcode, it can predict certain things like the player's own movement, weapon firing, and sounds. Entities outside the player aren't predicted, so other players, enemies, etc all have one state.

For prediction, there are two copies of the player's state, one for the predicted outcome, another is the "real" state. So, let's say we got PlayerData_t realPlayer, and PlayerData_t predictedPlayer.

The prediction works by running the same code as the real state, but with pointers changed to target our predicted struct, rather than the real one, and once the network catches up, the predicted state is rolled back to the new values of the real struct and replayed/corrected with this new information.

In this game, there's a member of PlayerData_t used for display-related code, like one for light flashes. Let's call this "flash". "Flash" is decremented in the drawing code to fade out the light relating to the flash. The drawing code obviously doesn't operate in lockstep with our sim. Any object can set a player's flash value, such as explosions.

In our display code, if we use predictedPlayer->flash as our source, only flashes from predictable code ever show up, so... like firing weapons. Since explosions aren't predicted, it never sets it (realPlayer->flash gets set). If we use realPlayer->flash as our source, flashes for firing the player's own gun, show up late (ie, when the network catches up).

If we do predictedPlayer->flash = realPlayer->flash just before rolling back and replaying/correcting the prediction, we get some nasty flicker, because our display code only decrements predictedPlayer->flash, while the sim sets realPlayer->flash and predictedPlayer->flash.

If we move our flash member to a new struct for display-related things, and modify that, we get flicker for another reason: Predicted code sets it, display code starts decrementing it, real code then sets it back again when the network catches up, it's then set back YET AGAIN when the rollback & replay happens.

So, what can I do? Is there some way I can merge both realPlayer->flash and predictedPlayer->flash, and have it only show once per occurrence? Hopefully, this is a clear enough explanation of what's going on. If not, I can try to clarify with some code snippets.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.