2. Physics / Authority transfer

In this sample we look at how to network simple physics simulated directly on the Clients, and the implications of this setup.

If we were making a game that relied on precise physics at play between the players (like a sports match, for instance), we would probably go with a setup where the Clients connect to a Simulation Server that runs the physics and prevents cheating.

However, that makes running the game much more expensive for the developer, since a Simulation Server has to be always-on.

Controls

  • WASD or Left stick: Move character

  • Hold Shift or Shoulder button left: Run

  • Spacebar or Joypad button down: Jump

  • E or Joypad button left: Pick up / throw objects

Topics covered

Physics | Authority transfer | Uniqueness | Persistence

In this scene...

In this scene we have mostly static scenery, and a few crates that the players can pick up and throw around. Who runs the physics simulation here? You could say that everyone runs their part. Let's take a closer look into the setup.

How it's set up

Select one of the crates in the scene. You can see that they have normal Box Collider and Rigidbody components. Up until a player is connected, they are being simulated locally. In fact if you press Play, they will fall down and settle.

The crates also have a CoherenceSync component. The first player to connect gets authority over them, and keeps running their simulation without interruption. That Client now syncs 2 values over the network: Transform.position and Transform.rotation.

On other Clients however (the ones that connect after the first), these crates will become remote. The configured component action makes their Rigidbody kinematic, so that now their movement is controlled by the remote authority (i.e. the first Client).

Authority switch

At this point, the first Client to connect is simulating all the crates. However, interacting with physical objects that are simulated by another Client is quite unpleasant due to the lag. To make it better, other Clients steal authority over crates, whenever they either:

  • Touch/collide with a crate directly

  • Pick a crate up

In code, this authority switch is a trivial operation, done in a single line. You can find the code in the NetworkGrabbable class:

private void OnCollisionEnter(Collision collision)
{
    if(!_sync.HasStateAuthority)
    {
        _sync.RequestAuthority(AuthorityType.Full);
    }
}

As you can see, it's good practice to ask first if the requesting script already has authority over an object, to avoid wasted work.

Once the request succeeds, the instance of the crate on the requesting Client becomes authoritative, and the Client starts simulating its physics. On the other Client (the previous owner), the object becomes remote (and its Rigidbody kinematic), and is now just receiving position and rotation over the network.

Careful! Since authority request is a network operation, you can't run follow-up code right away after having requested it. It's good practice to set a listener to the events that are available on the Coherence Sync component, like this:

_sync.OnStateAuthority.AddListener(OnStateAuthority);
_sync.OnStateRemote.AddListener(OnStateRemote);

This way, as soon as the reply comes back, we can perform the rest of the code.

So who is running the physics, after all? We can now say that it's everyone at the same time, as the roles change all the time.

As we mentioned in the intro - in a simple game where precise physics are non-crucial this might be enough, and it will definitely keep the costs of running the game down, since no Simulation Server has to run in order to make the game playable.

As before, pressing Tab (or clicking the Joystick) switches to an authority view. It's very interesting to see how crates switch sides when a player interacts with them.

For more on authority, take a look inside the NetworkGrabbable class. It has more code regarding authority events, all commented.

About uniqueness and persistence

There is one important thing to note in this setup. Since the objects are already in the scene at the start, by default every time a Client connects it would try to sync those instances to the network. This is very similar to what we have seen with character instantiation so far: each Clients brings their own copy.

However, in this case this would effectively duplicate the crates, once online. One extra copy for each connected player! We don't want that.

For this reason, the CoherenceSync is configured so that these crates are Persistent and have No Duplicates. This is generally the correct way of configuring networked Prefab instances that have been manually placed in the scene.

With these parameters in mind, the way the crates behave is as follows:

  • At the start, none of the entities exist on the Replication Server (yet).

  • The first Client connects. They sync the crates onto the network. Being unique, the Replication Server takes note of their Universally Unique ID (UUID).

  • Another Client connects. They try to bring the same crates onto the network, but because they are set to be No Duplicates and coherence finds there is already a network entity with the same UUID, it destroys the instance in the scene and network-instantiates a new instance, which is now non-authoritative.

  • If the first Client disconnects, the crates are not destroyed because their Lifetime is set to Persistent. They briefly become orphaned (no one has authority on them) but immediately the authority is passed to the second Client due to the option Auto-adopt Orphan being on.

  • If everyone disconnects, the crates persist on the Replication Server as network entities that are orphaned. They keep whatever position/rotation they had, since nobody is simulating them anymore.

At this point, nobody is connected. The Replication Server is not doing any work.

  • When a new Client reconnects and tries to bring the crates online, a duplication is detected: the Prefab instance in the scene and the network instance on the Replication Server have the same UUID. Due to Uniqueness set to No Duplicates, their local instances are destroyed and re-instantiated as network copies. They are orphaned, but thanks to Auto-adopt Orphan, the Client immediately assumes authority on them.

  • They will also most probably see the crates snap to the last seen position/translation that was stored on the Replication Server, which is synced just before they assume full control over the crates. At this point, they start simulating their physics locally.

For more information on persistence, there's a whole lesson about it.

Last updated