Synced Variables

A synced Variables is a storage container that automatically synchronizes data between players, such as a number, a location, or a text.
For example, if you want to create a ranking list so that all the players in a room can view the same score records, you can use synced variables to store players and their scores.

Supported Variable Types

  • Currently, the following variable types are supported: bool, byte, short, int, long, float, double, string, Vector2, Vector3, Quaternion

  • List and Dictionary can be declared. The key types of Dictionary can be byte, short, int, long, or string. The value types of both List and Dictionary can be any of the types above.

Create Variables

  • Start with ---@varSync, which means to declare a synced variable.
---@varSync intValue:int
---@varSync floatValue:float
---@varSync boolValue:bool
---@varSync vectorValue:Vector3
---@varSync listSync:List<int>
---@varSync dictionarySync:Dictionary<int,string>
---@end
907

synced variables are labeled with (sync).

The owner of the game object synchronizes these variable values, whose changes are then sent to other players.

Changing and Using Variables

You can use SetValue to assign a value to a variable, and GetValue to get the value of a variable.
Note that unlike with common variables, you cannot assign a value to a synced variable directly using an equal sign (=).

function OnNetSpawned()
    --------------- example for single value ---------------
    -- get current stored stored synced variable
    local val = vectorValue:GetValue();
    print("current storage value",val);
  	vectorValue:SetValue(UnityEngine.Vector3(1,2,0));
  
  	intValue:SetValue(1);
  	floatValue:SetValue(1.5);
  	boolValue:SetValue(false);
end

When Variables Change

When a variable gets changed by the owner, other players in the room will all receive the changes. If you have something you need to do when a variable is changed, you can listen in on the changes using the variable’s OnValueChange event function.
Note that the OnValueChange event function is often registered in the ParaScript.OnNetSpawned event function because the event indicates that the network objects have been initialized and that the follow-up logic can be executed. If the event function gets registered before the network objects have been generated, it may cause an error during execution.

function OnNetSpawned()
    intValue:OnValueChange(function(curVal,preVal)
        print("intValue changed, current value = ", curVal, ", previous value = ", preVal);
    end);
  
  	-- If you need to use the previous value, 
    -- you can define variable records in the OnNetSpawned function
  	local preList = {};
    listSync:ForEach(function(value,idx)
        table.insert(preList,value);
    end);

    listSync:OnValueChange(function()	-- Note: List and Dictionary have no parameters.
      	-- Using listSync,read current value
        for i=0,listSync:Count() - 1 do
            print(string.format("current array index:%d %s", i, listSync:GetValue(i)));
        end
        
        -- you can iterate the array use ForEach, 
        -- the ForEach will break when the iteration function return true.
        listSync:ForEach(function(value,idx)
            print(string.format("current array index:%d %s", idx, value));
        end);
        
        -- Using preList
        for i,value in ipairs(preList) do
            print(string.format("previous array index:%d %s", i, value));
        end

      	-- Remember to assign the value to preList
        preList = {};
        listSync:ForEach(function(value,idx)
            table.insert(preList,value);
        end);
    end);
end

Use List

---@varSync listSync:List<int>
---@end

function OnNetSpawned()
    --------------- example for List ---------------
    -- get value at index
    local arrIdx = 0;
    listSync:GetValue(arrIdx);

    -- set value at index
    listSync:SetValue(arrIdx,111);

    listSync:OnValueChange(function()
        for i=0,listSync:Count() - 1 do
            print(string.format("current array index:%d %s",i, listSync:GetValue(i)));
        end

        -- or you can iterate the array use ForEach, the ForEach will break when the iteration function return true
        listSync:ForEach(function(value,idx)
            print(string.format("current array index:%d %s",idx, value));
        end);
    end);

    -- clear storage
    listSync:Clear();

    -- Append value 
    listSync:Add(200);

    -- insert element at index
    listSync:Insert(arrIdx,400);

    -- remove element
    listSync:RemoveAt(arrIdx);
end

Use Dictionary

---@varSync dictionarySync:Dictionary<int,string>
---@end

function OnNetSpawned()
    --------------- example for Dictionary ---------------
    local dicKey = 100;

    -- add or change dictionary value
    dictionarySync:SetValue(dicKey,"dic value");

    if dictionarySync:ContainsKey(dicKey) then
        print("check dictionary has key",dictionarySync:GetValue(dicKey)); 
    end

    -- remove dictionary item
    dictionarySync:Remove(dicKey);

    -- clear storage
    dictionarySync:Clear();
    
  	-- listen dictionary value change
    dictionarySync:OnValueChange(function()
        -- iterate the dictionary
        dictionarySync:ForEach(function(value,key)
            print(string.format("dictionarySync value changed key:%s value:%s",key,value));
        end);
    end);
    
    local dictionaryEleCount = dictionarySync:Count();
		print("dictionarySync contain element",dictionaryEleCount);
end