【VRChat】Introduction to Network Synchronization: Understanding Ownership and UdonSynced

Created: 2025-12-19

The fundamentals of network synchronization at the core of VRChat multiplayer. Object ownership, [UdonSynced] variables, and the mechanism of data sharing through RequestSerialization.

Overview

The greatest appeal of VRChat is that multiple players can share the same experience in the same space. When one player presses a button, a door opens in everyone else's view too. This is possible because of a mechanism called network synchronization.

Network synchronization in UdonSharp may seem complex at first glance, but once you understand a few basic concepts, the mechanism becomes very clear. This article covers the following three core elements essential for creating multiplayer-compatible gimmicks:

  1. Ownership: Who has the right to manipulate that object.
  2. Synced Variables ([UdonSynced]): Variables shared between players.
  3. Serialization: The process by which data is actually synchronized over the network.

1. Ownership - "Whose Object Is This?"

Every GameObject in a VRChat world always has exactly one Owner. The owner is the player who has the authority to freely change that object's state and notify other players of those changes.

  • Default Owner: The owner of objects placed in the world from the start is the person who created the world instance (Master).
  • Ownership Rule: Only the object's owner can change synced variable values. Even if a non-owner player tries to change a value, that change remains local (only to themselves) and won't be transmitted to other players.

This rule that "only the owner can make changes" is the fundamental mechanism that prevents state confusion when multiple players try to manipulate the same object simultaneously.

How to Acquire Ownership

When creating a gimmick where a player manipulates an object, that player first needs to become the object's owner. To acquire ownership, use the Networking.SetOwner() method.

Networking.SetOwner(VRCPlayerApi player, GameObject obj);

  • player: The player who will become the new owner. Usually yourself, i.e., Networking.LocalPlayer.
  • obj: The GameObject you want to acquire ownership of. Usually the object the script is attached to, i.e., gameObject.

This method is typically called when a player takes some action on an object (e.g., Interact).

public override void Interact()
{
    // Set ownership of this object to myself (local player)
    Networking.SetOwner(Networking.LocalPlayer, gameObject);

    // ... Write processing to change synced variables after this ...
}

2. Synced Variables ([UdonSynced]) - Data Shared by Everyone

For variables you want to share between players, add the [UdonSynced] attribute immediately before the declaration. This tells Udon that the variable is "subject to network synchronization."

using UdonSharp;
using UnityEngine;

public class SyncedVariableExample : UdonSharpBehaviour
{
    // This bool value is synchronized among all players in the instance
    [UdonSynced]
    private bool isLightOn = false;
}

There are restrictions on variable types that can have [UdonSynced], but many basic data types are supported, including int, float, bool, string, Vector3, Quaternion, and Color.

3. Serialization - The Data Sync Process

Variables with the [UdonSynced] attribute are synchronized to all players through the following process. This entire flow is called Serialization.

  1. Acquire Ownership: Player A manipulates the object and becomes the owner with Networking.SetOwner().
  2. Change Synced Variable: Player A (owner) changes the [UdonSynced] variable value. (e.g., isLightOn = true;)
  3. Request Serialization: Player A calls RequestSerialization(). This is a request saying "The variable value has changed, so please send this data to everyone else."
  4. Send Data: VRChat's server sends the new variable data (serialized data) from Player A to all other players in the instance (Players B, C, ...).
  5. Deserialization: The Udon VM of other players (B, C, ...) who received the data automatically calls the OnDeserialization() event. At the point this event occurs, their [UdonSynced] variable values have been updated to the new values set by Player A.
  6. Reflect State: In the OnDeserialization() method, write processing to update the world state (e.g., turn on the light) based on the updated variable values.

Implementation Example: Synced Switch

Let's look at this process with a synced switch that toggles a light ON/OFF when clicked.

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;

public class SyncedSwitch : UdonSharpBehaviour
{
    public GameObject targetLight;

    [UdonSynced]
    private bool isLightOn = false;

    void Start()
    {
        // Reflect initial state
        UpdateLightState();
    }

    public override void Interact()
    {
        // 1. Acquire ownership
        Networking.SetOwner(Networking.LocalPlayer, gameObject);

        // 2. Change synced variable
        isLightOn = !isLightOn;

        // 3. Request to notify all players of the change
        RequestSerialization();

        // Immediately update own appearance as well
        UpdateLightState();
    }

    // 5. Called when data is updated on other players
    public override void OnDeserialization()
    {
        // 6. Reflect updated state
        UpdateLightState();
    }

    private void UpdateLightState()
    {
        if (targetLight != null)
        {
            targetLight.SetActive(isLightOn);
        }
    }
}

In this code, the player who Interacts changes the value and notifies with RequestSerialization(). Other players receive the notification in OnDeserialization and call UpdateLightState(), ensuring everyone's light state matches.

Summary

  • The foundation of network synchronization is Ownership. Only the owner can change synced variables.
  • When a player manipulates an object, first acquire ownership with Networking.SetOwner().
  • Add the [UdonSynced] attribute before variables you want to share between players.
  • When the owner changes a synced variable's value, call RequestSerialization() to notify of the change.
  • Other players receive the change in the OnDeserialization() event and update the world state.

This flow of "Acquire Ownership → Change Value → Notify → Receive and Update" is the most fundamental pattern for network synchronization in UdonSharp. Understanding this pattern is the first step to creating multiplayer-compatible gimmicks.

The next article will cover "Methods and Custom Events" for inter-script communication.