Why are multiplayer games are laggy

Hello everyone, I am Unity developer for 3 years, and for last two weeks I’ve been tinkering with multiplayer in 3d in which players move freely and throw objects to each other so I am trying to keep other players updated of locations of players and moving objects, I’ve found some platformer and fps examples online but even in I test them on two PCs in same network I can clearly see lagging, players being teleported here and there on every one of them, I’ve tried projects with libraries like UNet, Mirror.

I want to ask if it is normal, I know i shouldnt judge performance by some example projects but this seems like a hard case shouldnt these libraries handle this kind of issues, I mean I’ve heard in a video that we should calculate latency and move player with that delta time in other clients, but if we are gonna do these manually why do we have high level multiplayer libraries, or do every people I’ve checked projects have very good modem at their house so they dont require this kind of optimizations?

Also I am playing a lot of online fps games on my PC so I dont think I’ve problem with modem or internet speed (also in this case I am going outside my network which should be much harder task)

This is the cost for multiplayer games, position is not sent to clients every frame to minimize the network bandwidth, you can send every frame but you will run out of bandwidth very fast, especially if there are more players that require position update. If you use NetworkTransform you have to play with the parameters until you get something acceptable. If you make your own network transform or you send the position manually, to solve the laggy feeling, when a client receives a new position don’t set it directly but use a Vector3.Lerp(current position, last received position) to smooth the movement, or you can use forces by sending the velocity that the player has and you move the player on all clients independently in Update(), but you need to be carefull because this method (with forces) can create position missmatches between clients and you have to check frequently for them and snap the players to correct position when they deviate too much.

A proper network solution is a quite hard topic and can not be solved in a generic matter. Please keep in mind that the world does not consist of just FPS games. So a generic network library can not make assumptions for every possible usecase. That’s why most of those libraries are just high level libraries which offer tools to abstract the transmission of data. Your usecase specific optimisation has still be done by yourself. For example one of my all time favourite network FPS game is Quake 3. The network design works just perfect. The server sends out snapshots of the whole game, individually for each player. That includes a trimmed down set of data of only those things which are visible / relevant for each client. This of course involves the players own position and what’s around him. So the server does essentially perform a “visibility” check for all objects. Though Quake uses a BSP based map that is split into sections. So the server even tells the client which sections are visible to him.

One important detail is that every network message has a timestamp. So the server is able to reduce the response time by half the players ping time by going back in time when a message arrives. So the player hits the fire button at time “x” but that message arrives at the server at time “x+p” where p is the one way latency. At the moment the message arrives the server can “rewind” the movement on the server for the relevant objects and perform the hit detection so it matches pretty much exactly what the client has seen “p” seconds ago when he hits the fire button. Likewise the snapshot interpolation has a more or less fix time offset. Though the way the movement is realised allows several optimisations.

Quake does essentially send input changes / states and the desired target velocity. Since the actual velocity does “slowly” ramp up / accelerate there are also room for optimisation. Since the server knows when the user pressed down “W”, the server can again look back in time and adjust the velocity depending on how much time it took until the packet arrived at the server. Of course those trips into the past are only in the range of max 100ms, otherwise a cheater could essentially fake a “delayed” packet and tells the server he actually shot you 3 minutes ago -.-.

It’s interesting to see how the acceleration behaves when you are on an extreme high latency server. For example 200ms ping. Besides interpolating between the last two snapshots, the client also extrapolates into the future, but only in some rare cases. Usually the client on purpose lags behind the server a bit in order to get a smooth gameplay.

All this can get quite complex and as I said there’s no one-size-fits-all solution. If you can’t create such a system on your own, you may look out for some implementations you can use.

Note that the Q3 source code is open source now. However it has been released under GPL, so you can not use the code directly in a closed source project. So be careful to not “be inspired too much” by the original code or you may face legal issues. Though to learn basic concepts it’s always great to have such examples available. Always keep in mind to never copy or one-to-one translate such code. Read it, learn and understand what it does, take a week break and just implement it yourself freely without looking back at the original code. If you do you most likely will copy the original by accident ^^.

Try Photon Bolt and set interpolation on the transform