Network Variables are a way to synchronize state between clients in a persistent way, unlike Remote Events which are messages that are only processed by clients that are currently connected. Late-joining clients will catch up on the current state of Network Variables when they connect to a server instance.
public NetworkVariable<float> jetpackFuel { get; } = new();
public override void Spawned()
{
Debug.Log($"Player spawned with health: {_health.value}");
}
private void Update()
{
// Actor who has control (state authority) can modify the variable
if (hasControl)
{
if (Input.GetKeyDown(KeyCode.Space))
{
// Modifying the variable will automatically synchronize the change to other clients
jetpackFuel.value -= 10 * Time.deltaTime;
}
}
}
}
Variables must be initialized when declared to prevent null reference exceptions.
NetworkVariable<int> health = new();
NetworkVariable<int> jetpackFuel; // will throw null reference exception
NetworkVariable<int> health = new();
NetworkVariable<int> jetpackFuel; // will throw null reference exception
By the time Spawned() is called on the behaviour, all Network Variables will have been initialized and are ready to be used. Do not interact with Network Variables in Awake() or Start() as they may not be initialized yet.
Optionally, initial values can be provided when creating a Network Variable. These initial values will be used when the associated object is spawned.
Each Network Variable is assigned a unique ID within the associated Network Object. IDs are automatically assigned to Network Variables before Spawned() is called if they are not explicitly specified. IDs are of type byte so they have a valid range of 0 to 255.
For example, for a Network Object with a single ExampleBehaviour component, the _health variable will be assigned ID 0 and the jetpackFuel variable will be assigned ID 1. The order of the variables in the class definition determines the ID.
public class PlayerBehaviour : SpatialNetworkBehaviour
{
private NetworkVariable<int> _health = new(); // ID 0
private NetworkVariable<float> _jetpackFuel = new(); // ID 1
// ...
}
public class PlayerBehaviour : SpatialNetworkBehaviour
{
private NetworkVariable<int> _health = new(); // ID 0
private NetworkVariable<float> _jetpackFuel = new(); // ID 1
// ...
}
If the Network Object has multiple Network Behaviours, the IDs are assigned based on the order of the behaviours in the object.
// For a GameObject with a NetworkObject component and two Network Behaviours attached (PlayerBehaviour
// first, then PlayerMovement), the IDs will be assigned as follows:
public class PlayerBehaviour : SpatialNetworkBehaviour
{
private NetworkVariable<int> _health = new(); // ID 0
private NetworkVariable<float> _jetpackFuel = new(); // ID 1
// ...
}
public class PlayerMovement : SpatialNetworkBehaviour
{
private NetworkVariable<float> _speed = new(); // ID 2
private NetworkVariable<bool> _isSliding = new(); // ID 3
// ...
}
// For a GameObject with a NetworkObject component and two Network Behaviours attached (PlayerBehaviour
// first, then PlayerMovement), the IDs will be assigned as follows:
public class PlayerBehaviour : SpatialNetworkBehaviour
{
private NetworkVariable<int> _health = new(); // ID 0
private NetworkVariable<float> _jetpackFuel = new(); // ID 1
// ...
}
public class PlayerMovement : SpatialNetworkBehaviour
{
private NetworkVariable<float> _speed = new(); // ID 2
private NetworkVariable<bool> _isSliding = new(); // ID 3
As you may guess, changing the order of variables in a Network Behaviour class, or adding new variables will change which IDs are assigned to the variables. This can cause issues when trying to maintain compatibility with clients that are on previous versions of the package: "health" on Client A which is on version 1 of the package might be "jetpackFuel" on Client B which is on version 2 of the package.
To maintain compatibility, you can manually assign IDs to Network Variables. However, maintaining compatibility between versions can be complex and error-prone. Careful consideration should be given to which Network Behaviours are used together, as variable IDs may conflict if two Network Behaviours have variables with the same ID.
public class PlayerBehaviour : SpatialNetworkBehaviour
Network Variables can also be used with Visual Scripting. In general you should prefer using C# for multiplayer logic, as Visual Scripting incurs a big performance overhead. However, for simple use cases, Visual Scripting can be used to interact with Network Variables.
To add Visual-Scripting variables to a Network Object, use the Add Network Variables button on the Network Object component.
This will automatically add a Variables component to the Game Object where you can define the variables. If any of the variables are of the supported types, you can enable synchronization for them individually.
To set a network variable from a Visual Scripting scripting graph, use the Set Object Variable node.
Visual scripting variables will be assigned IDs at editor time. You can see these IDs in the Network Object inspector. If you manually assign IDs to C# Network Variables, you should ensure that the IDs do not conflict with the Visual Scripting variables.
Generally, this is advised against, as the performance overhead of Visual Scripting is significant. If you need to set Visual Scripting variables from C# code, ask yourself if you can achieve the same result using full C# code for the network object logic.
If you still need to set Visual Scripting variables from C# code, you can get the Unity.VisualScripting.Variables component and update variable values directly. The changes will be detected by Spatial and synchronized if they are marked as synced.
private void SetVisualScriptingVariableExample()
{
// Unity.VisualScripting.Variables: If this type is not found, make sure your C# assembly is
// referencing the Unity.VisualScripting.Core assembly
var variables = GetComponent<Unity.VisualScripting.Variables>();
// Set the value of a Visual Scripting variable
variables.declarations.Set("myVariable", 42);
}
private void SetVisualScriptingVariableExample()
{
// Unity.VisualScripting.Variables: If this type is not found, make sure your C# assembly is
// referencing the Unity.VisualScripting.Core assembly
var variables = GetComponent<Unity.VisualScripting.Variables>();