-
Notifications
You must be signed in to change notification settings - Fork 463
Description
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
NetworkBehaviourwith aNetworkVariable<float>(default value 0). - Override
OnNetworkSpawn. Inside the method, checkif (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
NetworkVariableon the Client side inside the Client'sOnNetworkSpawnmethod 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.Initializecaptures the default value (0) asm_PreviousValueand setsm_HasPreviousValue = true. - User Code:
OnNetworkSpawnis called on the Server. The user setsTestVal.Value = 2. This marks the variable as Dirty, butm_PreviousValueremains 0. - Serialization: When creating the
CreateObjectMessage,NetworkVariable<T>.WriteFieldSynchronizationis 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" value2is queued for a delta update. The client initializes with0before the delta arrives.