Synced Object

The Synced Object component lets you mark a scene object or prefab as replicated. The object's transform, lifetime, and custom variables will be synced across all clients in a server instance.

Warning

This component has been deprecated. Please use Network Objects instead. Synced Objects will continue to work and migrating is not strictly necessary, but we recommend using Network Objects for new projects. Check out the Migration Guide for more information.

Synced Object component

How To Use

Synced Objects can either be embedded in a scene or be instantiated as a prefab using visual scripting. The core behavior of the component acts the same between the two, but the following properties have slightly unique behavior depending on how the object is created.

Embedded Space Objects

Creating an embedded synced object is as simple as just adding a Synced Object component to any of your scene objects. From the hierarchy view, you can easily see which objects are synced by looking for the sync icon on the side.

Synced Object: sync icon

Prefab Objects

Creating a synced prefab is just as easy but requires a few extra steps. First, create a prefab that has a Synced Object component on the root object like so:

Create prefab with Synced Object component

This prefab can live anywhere in your project folder. To instantiate this prefab, you can simply use the GameObject.Instantiate node like normal. Spatial will make sure the object gets instantiated on all other connected clients and syncs properly.

Instantiate Synced Object

Network Variables

You can optionally enable network variables on your synced object. This allows you to keep Visual Scripting variables synchronized on the same object.

Network Variables follow the same ownership rules as the transform.

Currently the following variable types are supported:

  • Primitives: bool, byte, int, float, double, long, string
  • Unity types: Vector2, Vector3, Color32

Note

Network Variables were previously called Synced Variables.

Properties

See the API reference for a full list of properties.

Save with Space

If checked, the value of this variable will be saved with the space. This means that when a user leaves and rejoins the space, the value of this variable will be the same as when they left.

If unchecked, the behavior of the object is different depending on how it was created:

  • Embedded scene objects: When a new session starts (such as switching servers), embedded scene objects will always be instantiated, even if they where deleted in a previous session.
  • Instantiated prefab: When a session ends all instantiated prefabs will be deleted. In other words, the synced objects are maintained by the server instance, and teleporting to another server instance will not carry over the instantiated prefabs.

Note

Currently, only the "host" server instance (the first server that spawns) will save variables. Non-host server instances will not save variables; their values will be lost.

Master Client Object

If checked, this object will always be owned by the master client. If a new actor is designated as the master client, the ownership of this object will be transferred to the new master client.

Destroy on Creator Disconnect

If checked, the object will be destroyed its creator actor disconnects.

This property is not available for synced objects embedded in the scene.

Destroy on Owner Disconnect

If checked, the object will be destroyed if the current owner of the object disconnects.

This property is not available for synced objects embedded in the scene.

Limitations

  • Only the local transform is synced: If you re-parent a synced object on one client, that change will not propagate to the other. The synced object will still behave normally, but it's position might become de-synced since it will be relative to its parent.
  • A synced object can not be a child of another synced object.

Scripting with Synced Objects

When working with synced objects, it's important to keep in mind the rules of object ownership.

Here's an example of an object that follows its owner and can be picked up by other users, which helps explain the concept of object ownership.

Carry-able Object Example

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.

  1. Create a Synced Object
    • 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.
  2. Make the object follow its owner
    • 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
  3. Allow other users to take ownership
    • 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. interactable interactable graph
  4. Hide the Interactable when not owned
    • 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. on owner changed event

Migration Guide

This guide will help you migrate from Synced Objects to Network Objects.

Note

Network Objects do not currently support "Save with Space". If you need this feature, you should continue using Synced Objects.

Component Migration

Converting the component is made easy with the Convert to Spatial Network Object button. This will take all of the properties from the Synced Object and apply them to the Network Object, then remove the Synced Object component. Note that this button is only available if you do not have the "save with space" option set.

This operation is undoable, but it's always a good idea to make a backup or use version control for your projects when making large complex changes.

Convert to Spatial Network Object

You will need to manually fix any references you may have in the scene or prefab to this component if it was referenced through custom C# code.

Visual Scripting Migration

If you have visual scripting graphs logic, you will need to replace the Synced Object nodes with the equivalent Network Object nodes.

Synced Object NodeNetwork Object Node
Game Object Instantiate(Coroutine) Network Object: Spawn
Synced Object: Takeover OwnershipNetwork Object: Request Ownership
Network Object: Release Ownership
Synced Object: If Owned LocallyNetwork Object: If Has Control
Synced Object: Get By IDNetwork Object: Find Object
Synced Object: Get Is SyncedNetwork Object: Get Is Spawned
Synced Object: Get IDNetwork Object: Get Object ID
Network Object: Get Is Mine
Synced Object: Get OwnerNetwork Object: Get Owner Actor Number
Synced Object: Get Has ControlNetwork Object: Get Has Control
Synced Object: On Owner ChangedNetwork Object: On Owner Changed
Synced Object: On Object InitializedNetwork Object: On Spawned
Network Object: On Despawned

To replace a node, you can right click the node and click Replace... button.

Replace node

Since Visual Scripting Graphs are serialized as JSON you can search your project for any occurrences of these nodes using a text editor like Visual Studio Code, which will help you find all the places you need to update. The nodes are referenced by their C# class type, like "$type":"SpatialSys.UnitySDK.VisualScripting. SpatialSyncedObjectEventOnOwnerChanged", so you will need to search for the class names instead of the above node names. Here are all the node types you may want to scan for:

GetSyncedObjectByIDNode
GetSyncedObjectHasControlNode
GetSyncedObjectIDNode
GetSyncedObjectIsSyncedNode
GetSyncedObjectOwnerNode
IfSyncedObjectIsOwnedLocallyNode
SpatialSyncedObjectEventOnObjectInitialized
SpatialSyncedObjectEventOnOwnerChanged
TakeoverSyncedObjectOwnershipNode
GetSyncedObjectByIDNode
GetSyncedObjectHasControlNode
GetSyncedObjectIDNode
GetSyncedObjectIsSyncedNode
GetSyncedObjectOwnerNode
IfSyncedObjectIsOwnedLocallyNode
SpatialSyncedObjectEventOnObjectInitialized
SpatialSyncedObjectEventOnOwnerChanged
TakeoverSyncedObjectOwnershipNode

C# Scripting Migration

If you have any references to SpatialSyncedObject type in your C# scripts, you will want to replace them with SpatialNetworkObject. Don't forget about re-assigning any MonoBehaviour property references after you replace the types.

To customize a Network Object you write your own Network Behaviour script and attach it to the object. This gives you all the event hooks you need to handle equivalent functionality.

Here is the public api comparison between the two components:

Synced Object APINetwork Object API
SpatialSyncedObject.syncTransformSpatialNetworkObject.syncFlags
SpatialSyncedObject.syncRigidbodySpatialNetworkObject.syncFlags
SpatialSyncedObject.saveWithSpaceSave with space is not supported on Network Object
SpatialSyncedObject.destroyOnCreatorDisconnectSpatialNetworkObject.objectFlags
SpatialSyncedObject.destroyOnOwnerDisconnectSpatialNetworkObject.objectFlags
SpatialSyncedObject.isMasterClientObjectSpatialNetworkObject.objectFlags
SpatialSyncedObject.syncedObjectIDSpatialNetworkObject.objectID
SpatialSyncedObject.ownerActorIDSpatialNetworkObject.ownerActorNumber
SpatialSyncedObject.hasControlSpatialNetworkObject.hasControl
SpatialSyncedObject.isLocallyOwnedSpatialNetworkObject.hasControl
SpatialSyncedObject.TakeoverOwnershipSpatialNetworkObject.RequestOwnership
SpatialNetworkObject.ReleaseOwnership
SpatialNetworkObject.TransferOwnership
SpatialNetworkObject.TryFindObject
SpatialSyncedObject.isLocallyOwnedSpatialNetworkObject.hasControl
SpatialSyncedObject.onObjectInitializedThis has no direct equivalent, but you can get a Spawned() callback when you implement a Network Behaviour script
SpatialSyncedObject.isSyncedThis has no direct equivalent, but you can use a Network Behaviour script to set a public bool isSpawned { get; private set; } property on your behaviour that you can check externally
SpatialSyncedObject.onOwnerChangedOwnership change callbacks can be handled in a Network Behaviour script when implementing the IOwnershipChanged interface
SpatialSyncedObject.onVariableChangedVariable change callbacks can be handled in a Network Behaviour script when implementing the IOwnershipChanged interface