Networking model : enforced input lag to eliminate glitches from future prediction

Started by
0 comments, last by hplus0603 8 years, 3 months ago

Game environment : a vehicle control game, where the player constructs large voxel contraptions and drives them around in multiplayer.

I'd like for players to be able to leave their seats and run around in the vehicles while they are moving. I'd like the vehicles to be able to reach realistic speeds - hundreds of kilometers/second in the worst case - without any chance of players ever glitching through the floor or outside, etc, even if another player is at the helm. I'd like for 2 player controlled vehicles, both "moving" at ludicrous speeds, to be able to dock in space. I don't want there to be any visual glitches whatsoever - no warping, rubber banding, juddering, or the sky moving funny if one player is looking out the window while another player is on the helm.

I see one way to do this, but it has a cost and I'm unclear if this is the only option.

It's real simple. Player updates a GUI that controls a vehicle. It's indirect control - a player might click the mouse on the 'navball' to choose a new orientation, or choose a new setting on the throttle.

GUI updates instantly with a color indicating that the action hasn't actually started yet.

These GUI actions get sent via the usual UDP spam mechanism to the server. (50 times a second you send a new set of UDP packets containing any unacknowledged actions).

Server updates it's internal state/sim model from the GUI changes. Server now starts uploading to all clients a TCP message containing the new state of the game world, specific to the events each player has "subscribed" to. (player client has mandatory things it must subscribe to, things within a certain radius of the player model itself, and other stuff is by request by the player client.)

The new state is set in the "future". Clients now generate intermediate game states that are then used for rendering of the world, with the intermediate state series adjusted so it will always end up precisely aligned with the new state.

So the cost : input lag. About 500-1000 ms. Press a button to open a door? 500-1000 ms will pass, then the door starts opening. Summon a lift? Send the lift to a floor? Adjust course on a spaceship? All have a delay.

The benefit is that all players with pings below about 500 ms never see any glitches from the environment. Everything is always exactly where it really is, synchronized with the server, and everything should move smoothly. There would be no problems with doors or lifts when multiple players are using them, because every player shares the same game world in sync with everyone else.

Player models and things that can be affected by the player model in real time can't be done this way. If you see another player in multiplayer, you are not seeing where they are now, just where your client is guessing they are (future state prediction). So you would have to have the authoritative server pass through immediately in a separate thread any UDP state updates from other players. P2P would be even better.

This makes small bouncing objects the players can shove around extremely problematic : I cannot think of a perfect solution for them. Either they warp and rubber band and jitter to where the authoritative server says they are, or they have async and local which also creates edge case bugs.

Advertisement
Input lag doesn't have to be 500 ms until a player sees the action. It depends on your simulation frame rate, your network tick rate, and the player's proximity to the servers.

If the player is on the same continent as the server, that will be 100 ms round-trip time.
If the network tick rate is 50 Hz, and the simulation rate is 150 Hz, you will add 20 ms + 7 ms of additional round-trip latency, which sums up to 127 ms network-induced latency. Add one frame of display latency -- 17ms at 60 Hz -- and the grand total is 144ms.

You probably also want to use "swept body physics" for your collision detection, to make sure no two things glitch through each other when moving quickly. The "Bullet" open source physics engine is pretty good at this.

Also, you don't want to use TCP, because that will actually cause more glitching than UDP. For each network tick, provide all player inputs, and a checkpoint of the state of X vehicles. Rotate the X vehicles over time, and randomize which vehicles are included, so you don't always send the same X vehicles at the same time. The simulation will be eventually consistent, and you will very seldom see glitches, because if you miss a packet, you can assume that the input from the player was the same as last frame (Gas down then? Gas still down now!)

If you want exactly zero glitches, though, then you will be prepared to accept infinite latency. An infinite number of packets may be lost from (or to) one player until one gets through, which means that you need confirmation that all players have sent an update before you can send that update. This is related to why TCP is a poor choice -- you really cannot assume "perfect" gameplay in a networked game. All you can do is minimize the visible glitches (to near zero) and make everyone agree on what the world state is "on average" and "eventually" -- as in, when you drop a packet, your view of the simulation may be slightly off, but it will be repaired within limited time.

If you want to, you can send the full state of all vehicles in each packet, but that will be ... a lot of data.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement