Lag compensation and object ownership in Unity.

Hey Guys,

I am very experienced at low level game networking, but am trying to wrap my mind around Unity’s higher level functionality. The networking page is pretty vague, giving no actual implementation examples.

Some questions for those experienced with internet multi-player on Unity.

(1) How can one “lag compensate” PhysX controlled objects? what is the formula given a known set of parameters at a given point in time for the velocity and position at a later point in time?

(2) Under Non-Authoritative Server the networking page suggests: “There is no need for any kind of prediction methods as they clients do all physics and events themselves and relay what happened to the server. They are the owner of their objects and are the only ones allow tho send local modifications of those objects to the network.” How do you divide up ownership of objects in a shared world? Is it effectively random?

  1. Check out the “NetworkRigidbody.cs” script that comes with the Networking Example package from the resources section. In a nutshell, it keeps a buffer of the past twenty frames of position, rotation, velocity and angular velocity.

  2. With the built-in networking, if you use the stock Network.Instantiate() function to create objects across the network, the person who calls Network.Instantiate will own the networkviews on it, and can thus directly control input on it and will be the stream writer of any network serialization.

So in a non-authoritative game, you would let every client Network.Instantiate their own player objects so they control the objects and serialize the results to everyone else

In an authoritative setup, you would have the server do all the Network.Instantiates so he was the owner, and then you would need to come up with some sort of schema so the server can assign player objects to different clients, and then receive input requests from clients, move the objects, then sync the results back to everyone.

1 Like

Thanks.

Ill take a loo kat that class. Still, trying to infer the curve empirically is a whole lot less efficient then actually running the physics algorithm forward :confused:

The networking example isn’t actually a lag compensation solution. Its a latency buffering solution.

Latency buffering is an old technique employed mostly in order to make frame-locked games network playable where you give the game a constant lag that is greater then your expected maximum lag. This makes the game more playable because the response is consistant. It does however leave the game with a bit of a “driving the tugboat” feel where the results of player actions always lag behind the player input.

Latency compensation/correction is a more sophisticated technique where the lagged data on arrival is actually processed “forward” in time to find a predicted current state. The example does this to a VERY limited degree with what it calls “extraploation” but the window in which it can do this is limited because it cannot properly calculate the results of the physics calculations for drag and such.

A really good networking solution could be implemented if the actual forward physics calculation could be done. I am going to investigate the PhysX API level and see if there is a way to query it for that information.

Well you don’t actually ever have lag on your own input when you use NetworkInterpolatedTransform/NetworkRigidbody because you don’t run it on yourself (the owner of the object), you only run it on the remote copies of your object in the other instances of the game (in a non-authoritative setup).

I’m pretty sure that its inspired by the latency compensation from Source Engine games, from by this article.

Are you sure? That doesn’t make sense by the code to me.

If your local simulation is running at 'current time" then by definition you would NEVER be interpolating because, by definition, remote objects position is always arriving at a time LATER then when the move was made, which means the interpolation buffer is always talking about the past.

In order for them to be synchronized properly on your system, your system has to also be showing the past.

I’ll take a look at the article you pointed to.

Edit: As I thought…

“The trick to solve this problem is to go back in time for rendering, so positions and animations can be continuously interpolated between two recently received snapshot.”

You are never seeing the result of your current actions but rather those at a previous time. In the sample code, you send out your "current physics position’ to all participants, including yourself. You then set the displayed position of all objects at the point in time in the past equal to your latency buffering delay.

The latency buffering delay will always be there in your inputs. If its less then about 1/10th of a second its below human reaction time. Anything more then that can be felt by the user.

This is the reverse of dead reckoning, where rather then delaying your view into the past, you interpolate the view of others in to the future. LAtency buffering has the benefit of being more “correct” in that you don’t have to guess at the future, but has the disadvantage of introducing lag into the controls.

How much lag depends on how much worst-case latency you have to cover.

What Im trying to implement is a dead reckoning solution as I can handle lower precision in the results. Interestingly enough PhysX has support for this in that you can create a separate dead-reckoning “scene” and run it forward in time.

Unfortunately, once again, I seem to be stalled by the Unity API which hides all the direct PhysX calls :frowning:

This is an on going problem for me with Unity… that they have gone out of the way to make doing anything but the simpelst things difficult to impossible using their API :frowning: About the only solution I see is basically throwing out all of Unity’s physics and writing my own bindings that expose the PhysX level. Thats a lot of work, though, to cover what should be in their APi to begin with.

I never read the article too thoroughly, I just remember someone mentioning that those scripts were inspired by it. But I DO know that NetworkInterpolatedTransform/NetworkRigidbody do not introduce any input lag, you don’t even run them on the local client. They make it so that other clients see your position in the past, not the local client (the player, and owner).

In the networking example, check out the third person example, build out a standalone, and connect to yourself in two players side by side and test it for yourself. If you look at the “ThirdPersonNetworkInit.js” script, you can see:

function OnNetworkInstantiate (msg : NetworkMessageInfo) {
	// This is our own player
	if (networkView.isMine)
	{
		Camera.main.SendMessage("SetTarget", transform);
		[B]GetComponent("NetworkInterpolatedTransform").enabled = false;[/B]
	}
	// This is just some remote controlled player
	else
	{
		name += "Remote";
		GetComponent(ThirdPersonController).enabled = false;
		GetComponent(ThirdPersonSimpleAnimation).enabled = false;
		GetComponent("NetworkInterpolatedTransform").enabled = true;
	}
}

And if you tweak the “interpolationBackTime” variable, its plain as day that it only effects the delay in movement of the remote copies of your player object, not the local player’s (owner’s) instance.

If you do that then your scene is out of time synchronization with everyone else’s view of you. Thats bad in a physically simulated world

Imagine this…

TIme a:
I bounce of object C a its rest position, setting it in motion

Time a+n, where N less then the latency buffering constant (we can even say less then the true latency):
You bounce off object C at its rest position (because on your scene i havent gotten to it yet) and send it in a different direction.

Time b:
My packet arrives at your system and, after the preset lag-bfufer delay, sets MY vector for the object on your screen

Time c:
Your packet arrives at my system and, after the preset lag-buffer delay, sets YOUR vector fort the object.

You could cludge this and say that only one of us is allowed to con trol the object’s cannonical position and vector of motion, but now you have introduced double latency lag into it moving at all when the non-owner collides with it. The non owner has to collide on the owners system, which is lag-buffer delayed, and then the result has to be transmitted back to the collider and rendered, which is also lag-buffer delayed.

You could also cludge it by saying we can both effect it but one of us overrides the other. This however will cause potentially severe warping when such a conflict arises.

Personally, I just used the Multiplayer StarTrooper to answer my questions… It helps a ton

What I’ve learned is that, in the end, the lack of ability to call the PhysX API directly really ties one networking hand behind your back as it makes dead-reckoning impossible.

And thats too bad because its a fundamental technique essential to scaling simulations.

Thanks for the pointers.

It really depends on the game; I didn’t realize you wanted something that sophisticated. A truly synchronized networked physics implementation with Unity I think would be very hard to do (in fact, very hard to do in most any game engine). A lot current generation games like Gears of War, Halo, etc. in my experience handle lag compensation similar to what we talked about here, and when running physics, usually handle it client side for everyone (eg: when you blow up barrels or ragdolls in halo, different clients will see different results).

Yeah, it’s a ll good for ragdoll effects or barrel explosions to be different on each client, as it doesn’t really effect the gameplay, it’s just eye-candy. The problem comes when you have a game that relies on physics, like, as an example, a demolition derby game, where each player is a rigidbody and they are trying to hit each other, or a soccer game where the ball is a rigidbody.

Anyway, I am clueless about networking, but this lag compensation sounds pretty damn good, and pretty much necessary if you want to make a good multiplayer game. In trying to wrap my head around it all I came to the conclusion that if we could go into the future it would make a relatively lag free physics game much easier to obtain. Then I came across this, and cyberqat is saying that essentially we CAN do this, but not in Unity…

It doesn’t prevent a single thing. You can access the velocity, position and transforms of every single rigid body, and deal with it manually with sending and receiving packets.

If you want to have a mix of dead reckoning and instant input you can.

My suggestion is one like this:

  1. you press forward, and this makes your object move forwards locally, and sends both the current velocity and tells the server you are in fact, pressing forward.

  2. the server accepts this, and moves forwards with its own copy, and tells everyone else you’re moving forwards. Since it has your direction, its local code is able to accelerate and everyone else’s local copy is able to accelerate too.

  3. DR is used easy enough. You know the acceleration and timestamps of the packets, so the server’s model is a little bit ahead of time. It goes back and corrects the original player’s movement with some tweening, however remember - you also sent your inputs so it is far more accurate to “slide into place”. The initial movement is slightly out of sync, but because the server has your inputs and there is DR, it is able to guess accurately where you would have been on your screen when synching back to you and the clients.

No doubt you know all of this, but you do have the tools to do it manually in unity. You can override velocity and fine tune all the physx parameters as well as gather as much data as you need, so I am not sure why you think it is impossible.

I’d look forwards to a library written by someone who wants to take this sort of thing on for driving games, fps etc.

PrimeDerektive, your code example disables scripts on remote controlled objects.

I did this in my network design which is non-authoritative, and I use Network.Instantiate to spawn objects with physics scripts and a RIGIDBODY attached.

The rigidbody is running code on the remote controlled objects… which I think is fighting the OnSerializeNetworkView(bitstream) transform data…

I get jittery movement on remote objects. I thought it was network communications, but I don’t think so. I created a lerp to handle movement, and I get jittery movement even when it’s ONLY using lerp to move.

How are you supposed to turn off RIGIDBODY? Destroying it causes an error because scripts depend on it. I saw rigidbody.sleep, but it seems like it will automatically wake up if anything touches it?.. I’m not sure that’s right.

Is rigidbody causing my jitter? How are you supposed to design this?

Thanks

I think I have a workaround for the forward physics calculation:

using UnityEngine;
using System.Collections;

public class Simulate : MonoBehaviour {
    public float timeInFuture = 4.0f; //seconds to predict into th efuture
    // Use this for initialization
    void Start () {
        StartCoroutine (predict (timeInFuture));
    }
   
    // Update is called once per frame
    void Update () {
       
    }
    IEnumerator predict (float future) {
        float tScale = future / 0.1f;
        Time.timeScale = tScale; //set the timeScale to something fast
        yield return new WaitForSecondsRealtime (0.1f); //give Unity some time to do the calculation
        Time.timeScale = 0; //pause to see the prediction
    }
}
1 Like

Please tell me this actually works. I beat my head against this for so long in a pong implementation about a million years ago. I came away with the conclusion that it just was not possible to do proper lag compensation in Unity. I am for sure going to give this a try.

I don’t really understand the timing though, why .1 seconds? how long is necessary and what happens if you don’t wait long enough?

0.1f is just a random time I chose. The reason why you need to pick a time is because Unity needs time to calculate position using the new timescale. 0.1 seconds should be enough to predict everything for the next network update which is usually in 15ms or 0.015 seconds

Also, did the code work for you?

To solve the lag and latency problem, you have to use prediction using the previous speed, direction and latency for each player.

http://gabrielgambetta.com/fpm4.html