Table of Contents

Network Variables

Overview

Network Variables are a good option for sharing data between the different users of the simulation as they are automatically synchronized.

Unlike Session Properties that are accessed through methods to get or set values in the server, each Network Variable is referenced through an object that has to be instantiated. Also, each Network Variable exposes events that trigger when that variable's state changed

Each Network Variable is created with a unique identifier. This identifier is used by the Network Variable as the key in the Session Properties to store the variable's value. This means that, if more than one Network Variable is created with the same identifier, they will reference and overwrite the same Session Property.

When instantiating a Network Variable, its constructor accepts an initial value. When the Network Variable's initialization starts, it tries to retrieve its current value from the server. If the variable does not exist in the server, the local value is set to the one provided in the constructor. On the other hand, if the variable exists in the server, its value is retrieved and it is assigned to the variable's local value.

Supported data types

Network Variables can be of any type that can be serialized to Json.

For example:

  1. Primitive types: bool, byte, char, decimal, double, float, int, long, ulong, short, ushort...
  2. Custom serializable class with [Serializable] attribute and public properties.
  3. Arrays of serializable types or serializable classes.
Note

Unity types such as GameObject, Transform, Rigidbody, Material or any class inheriting from Component... are not supported.

Persistence

NetworkVariables by default keep their values until the session ends, that is, if our VIROO application is made up of several Unity scenes, their values will be kept between scenes. It is possible to make the variables persist only at scene level by registering them in the IScenePersistenceAwareElementRegistry interface.

public interface IScenePersistenceAwareElementRegistry
{
    void Register(IScenePersistenceAwareElement element);
    void Unregister(IScenePersistenceAwareElement element);
}

If, after creating a Network Variable, it is added to this registry:

  • The variable will call its Remove method when leaving the current scene to load a different one.
  • The variable will try to automatically retrieve its value if the application reconnects after a network disconnection.
Note

Remember to remove Network Variables from the registry in the OnDestroy method if you created them in a MonoBehaviour.

Usage sample

In this example, it is shown how to create a variable of type Integer with the Id myNetworkVariable. Remember that this Id must be unique, if another Network Variable is declared with the same Id, both of them will access the same data.

public class MyBehaviour : MonoBehaviour
{
    private NetworkVariable<int> myNetworkVariable;

    protected void Inject(IScenePersistenceAwareElementRegistry elementRegistry, NetworkVariableSynchronizer variableSynchronizer)
    {
        // we store the IScenePersistenceAwareElementRegistry to unregister later
        this.elementRegistry = elementRegistry;

        // we create the variable with myNetworkVariable id and 0 as the default value (if it has already been updated, the variable will retrieve its current value from the server instead of setting this default value)
        myNetworkVariable = new NetworkVariable<int>(variableSynchronizer, "myNetworkVariable", 0);

        myNetworkVariable.OnInitialized += OnVariableInitialized;
        myNetworkVariable.OnValueChanged += OnVariableChanged;

        // By registering the variable in the IScenePersistenceAwareElementRegistry what we do is to limit its persistence to the current scene, when the scene is left the variable will be removed from the server. If this code is run again after returning to the scene with this script, the variable will be created once again in the server
        elementRegistry.Register(myNetworkVariable);
    }

    protected void Awake()
    {
        // we call this method to have the Inject method automatically called by VIROO
        this.QueueForInject();
    }

    protected void OnDestroy()
    {
        // In order not to leave residual code, we will unsubscribe to the events we have previously subscribed to.
        if (myNetworkVariable != null)
        {
            myNetworkVariable.OnValueChanged -= OnVariableChanged;
            myNetworkVariable.OnInitialized -= OnVariableInitialized;
        }

        if (elementRegistry != null)
        {
            elementRegistry.Unregister(myNetworkVariable);
        }
    }

    // To change the value of our variable we only have to change the value of its `Value` property.
    public void IncrementValue()
    {
        myNetworkVariable.Value++;
        // at this moment, we cannot assure that the value has its value assigned (as we explain later), it can only be assured to have its value in the OnValueChanged event
        // all operations using the variables value should take place in the OnValueChanged event
    }

    // This event is called when the variable's value is set for the first time, or when it is restored after a successful reconnection after a network disconnection
    private void OnVariableInitialized(object sender, int value)
    {
        // Empty
    }

    // This event is called when the variable's value changes
    private void OnVariableChanged(object sender, int value)
    {
        // Empty
    }
}
Warning

As the variable is already synchronized automatically, it is necessary to be careful when assigning its value, making sure that only one client is in charge of doing it and not all of them.

Since users can create as many Network Variables as they need, in order to minimize the network traffic used to get or set their values, VIROO batches all Network Variable operations that occur in a frame and sends a single message to the server at the end of every frame if any operation takes place.

As a side effect of this batching process, after setting the value of a Network Variable it cannot be assured that, if you access its Value in the following line of code, its current value will be set. When setting its value, you should wait to the OnValueChanged event to be sure that you are using its current value.

That's why it is a good practice to move the logic that uses the variable's value to its OnValueChanged event's callbacks.