The following content were rewritten by AI to improve the readability.
Root Cause Analysis was done with Gemini CLI(model: gemini-3-pro), i personally manually check on it, though am not familar with the codebase, so please treat these findings as a starting point for further validation.
Description
When a NetworkVariable is modified within the OnNetworkSpawn method on the Server immediately after spawning a NetworkObject, the connecting Client receives the default/initial value (e.g., 0) in the initial CreateObjectMessage, rather than the modified value (e.g., 2).
Although the correct value is eventually synchronized via a subsequent NetworkVariableDeltaMessage, this causes a race condition where the Client sees the incorrect value during its own OnNetworkSpawn and initial frame execution.
Reproduce Steps
- Create a
NetworkBehaviour with a NetworkVariable<float> (default value 0).
- Override
OnNetworkSpawn. Inside the method, check if (IsServer) and set the variable to a new value (e.g., 2).
- Connect a Client to the Server/Host.
- On the Server, Spawn an instance of this object using
NetworkObject.Spawn().
- Observe the value of the
NetworkVariable on the Client side inside the Client's OnNetworkSpawn method or immediately after spawn.
- See error: The Client logs/uses the default value (0) instead of the server-set value (2).
Actual Outcome
The Client receives the default value (0) in the initial spawn packet. The correct value (2) arrives late in a subsequent delta update. This breaks initialization logic dependent on the initial state of NetworkVariables.
Expected Outcome
The Client should receive the modified value (2) contained within the initial CreateObjectMessage so that OnNetworkSpawn on the client has the correct state immediately.
Screenshots
If applicable, add screenshots to help explain your problem.
Environment
- OS: Windows
- Unity Version: Unity 6
- Netcode Version: 2.9
- Netcode Commit:
- Netcode Topology: Client-Server
Additional Context
Minimal Reproduction Code:
using Unity.Netcode;
using UnityEngine;
public class TestNetworkBehaviour : NetworkBehaviour
{
public NetworkVariable<float> TestVal = new();
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
if (IsServer)
{
// Server sets the value immediately upon spawn
TestVal.Value = 2;
}
else
{
// Client reads the value immediately
Debug.Log($"[Client] OnNetworkSpawn TestVal = {TestVal.Value}");
// EXPECTED: 2
// ACTUAL: 0
}
}
}
Root Cause Analysis:
We have investigated the internal execution flow and identified the issue in the serialization logic relative to OnNetworkSpawn timing:
- Initialization: When
Spawn() is called, NetworkVariable.Initialize captures the default value (0) as m_PreviousValue and sets m_HasPreviousValue = true.
- User Code:
OnNetworkSpawn is called on the Server. The user sets TestVal.Value = 2. This marks the variable as Dirty, but m_PreviousValue remains 0.
- Serialization: When creating the
CreateObjectMessage, NetworkVariable<T>.WriteFieldSynchronization is called.
- The Flaw: The logic checks:
if (base.IsDirty() && m_HasPreviousValue)
{
// Because it is Dirty, it assumes a delta update follows.
// It writes m_PreviousValue (which is 0) to the spawn message.
NetworkVariableSerialization<T>.Write(writer, ref m_PreviousValue);
}
else
{
base.WriteFieldSynchronization(writer);
}
- Result: The spawn message sends
0. The "new" value 2 is queued for a delta update. The client initializes with 0 before the delta arrives.
The following content were rewritten by AI to improve the readability.
Root Cause Analysis was done with Gemini CLI(model: gemini-3-pro), i personally manually check on it, though am not familar with the codebase, so please treat these findings as a starting point for further validation.
Description
When a
NetworkVariableis modified within theOnNetworkSpawnmethod on the Server immediately after spawning aNetworkObject, the connecting Client receives the default/initial value (e.g., 0) in the initialCreateObjectMessage, rather than the modified value (e.g., 2).Although the correct value is eventually synchronized via a subsequent
NetworkVariableDeltaMessage, this causes a race condition where the Client sees the incorrect value during its ownOnNetworkSpawnand initial frame execution.Reproduce Steps
NetworkBehaviourwith aNetworkVariable<float>(default value 0).OnNetworkSpawn. Inside the method, checkif (IsServer)and set the variable to a new value (e.g.,2).NetworkObject.Spawn().NetworkVariableon the Client side inside the Client'sOnNetworkSpawnmethod or immediately after spawn.Actual Outcome
The Client receives the default value (0) in the initial spawn packet. The correct value (2) arrives late in a subsequent delta update. This breaks initialization logic dependent on the initial state of NetworkVariables.
Expected Outcome
The Client should receive the modified value (2) contained within the initial
CreateObjectMessageso thatOnNetworkSpawnon the client has the correct state immediately.Screenshots
If applicable, add screenshots to help explain your problem.
Environment
Additional Context
Minimal Reproduction Code:
Root Cause Analysis:
We have investigated the internal execution flow and identified the issue in the serialization logic relative to
OnNetworkSpawntiming:Spawn()is called,NetworkVariable.Initializecaptures the default value (0) asm_PreviousValueand setsm_HasPreviousValue = true.OnNetworkSpawnis called on the Server. The user setsTestVal.Value = 2. This marks the variable as Dirty, butm_PreviousValueremains 0.CreateObjectMessage,NetworkVariable<T>.WriteFieldSynchronizationis called.0. The "new" value2is queued for a delta update. The client initializes with0before the delta arrives.