Netcode

Vocabulary

  • Client: A single connected user in a space. Each avatar in a space represents a single client*.*
  • Ownership: Responsibility for certain objects or state in a space.
  • State: Overarching term to describe data like transform positions and custom variables. State can be synced or un-synced depending on the context.

State is king

In Spatial, clients are synced through state updates. This means when a client modifies the position of a synced object for example, all other clients will receive a message like:

Object [Baseball]’s new position = (100,0,0)
Object [Baseball]’s new position = (100,0,0)

Each client will then set the position of their matching [Baseball] instance to match. In other words, the results of your code is synced rather than the code itself.

Object Ownership and Takeover

In Spatial, each Synced Object is owned by a single client*.* Only state changes made by the owner of the object will propagate to the rest of the connected clients.

By default, the original creator of an object is the owner. However, clients can request to takeover ownership of an object. Ownership lasts until the client disconnects, or another client requests ownership. When the owner of an object disconnects ownership is defaulted to one of the other connected clients.

Warning

If a client tries to modify the state of a synced object that they do not own, the change will be reverted during the next frame.

Object lifetime

The principles above also apply to the life of a synced object.

  • If a client Instantiates a synced object, all connected clients will create an instance of the same object locally.
  • If a client Destroys a synced object that they own, all connected clients will destroy their instance of the same object.
  • If a client Destroys a synced object that they don’t own, the object will be re-created to match the current synced state.

Synced Object Example

Using the above rules as guidance, let’s create a simple example where we take into account object ownership to create a properly coded synced object.

I want to make an object that follows a user around, but another user can “grab” it, in which it will follow that user instead.

Step 1

To get started we need to add a Synced Object component as well as a script machine to our object. The object in question is a scene object, so we don’t need to worry about instantiating it.

Step 2

Inside our script, we first want to write the code that updates the object's position. Remember that only the client that owns the object should be modifying the transform state.

To accomplish this we use the If Owned Locally synced object node. This lets us branch off the true port, causing the subsequent code to only be run when the local client owns the object.

The result of this will be an object that follows its owner.

script to update object's position

Step 3

Now we need to add the ability to claim ownership of the object. I accomplished this through adding a Spatial Interactable as a child to the object.

Then in VS we can use an On Interact event and trigger the Takeover Ownership synced object node. This means when a client uses the Interactable, they will become the owner of the object.

Netcode interactable

Netcode interactable graph

Step 4

Now we can actually improve this a little further. By using the On Owner Changed synced object event, we can enable/disable the Interactable to only be visible when we don’t own it.

Netcode on owner changed event