Unity-Technologies / com.unity.netcode.gameobjects

Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.
MIT License
2.15k stars 434 forks source link

Uninitialized network variable #2517

Open Wolframwow opened 1 year ago

Wolframwow commented 1 year ago

Description of bug:

I am trying to have a global component (network object) in the scene which acts as a "Tick generator" so that all players generate resources simultaneously. This component should invoke an event which is triggered by changing a network variable (already declared with value 0) , by the Server (NetworkManager). This component's prefab is also registered inside the NetworkPrefabs section of the NetworkManager. Warning caught when starting server:

"NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. Are you modifying a NetworkVariable before the NetworkObject is spawned?"

Even if the network variable changed, this won't get replicated to the clients. It has both network object and network behaviour and it is spawned. image

Reproducible?

Yes, in 50% of the cases. Sometimes the component works as intended.

Steps to reproduce:

Outcome: in 50% of the cases the warning appears, even if the The steps above should be repeated several times because it might not occur on the 1st try

Expected behavior: In the 50% of the working cases, there is no warning, and the network variable (from within this component) is getting replicated to the clients, which then get notified via this event.

Additional Remarks: The issue does NOT occur at all if it is spawned dynamically! As discussed on the discord channel, this might offer a better insight image

Environment used:

Network Manager setup: image

Component code used: Description of bug:

I am trying to have a global component (network object) in the scene which acts as a "Tick generator" so that all players generate resources simultaneously. This component should invoke an event which is triggered by changing a network variable (already declared with value 0) , by the Server (NetworkManager). This component's prefab is also registered inside the NetworkPrefabs section of the NetworkManager. Warning caught when starting server:

"NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. Are you modifying a NetworkVariable before the NetworkObject is spawned?"

Even if the network variable changed, this won't get replicated to the clients. It has both network object and network behaviour and it is spawned. image

Reproducible?

Yes, in 50% of the cases. Sometimes the component works as intended.

Steps to reproduce:

Outcome: in 50% of the cases the warning appears, even if the The steps above should be repeated several times because it might not occur on the 1st try

Expected behavior: In the 50% of the working cases, there is no warning, and the network variable (from within this component) is getting replicated to the clients, which then get notified via this event.

Additional Remarks: The issue does NOT occur at all if it is spawned dynamically! As discussed on the discord channel, this might offer a better insight image

Environment used:

Network Manager setup: image

Component code used:

public class D_TickHandler : NetworkBehaviour
{
    /// <summary>
    /// int: old tick value. int: new tick value
    /// </summary>
    public event Action<int, int> tickgenerated;
    [SerializeField] public static D_TickHandler singleton = null;
    [SerializeField] NetworkVariable<int> tickGenerated = new NetworkVariable<int>(0);
    public D_TickHandler()
    {
        if (singleton == null)
        {
            singleton = this;
        }
    }
    private void Awake()
    {
        tickGenerated.OnValueChanged += HandleValueChanged;
        DontDestroyOnLoad(this);
    }
    private void OnApplicationQuit()
    {
        tickGenerated.OnValueChanged -= HandleValueChanged;
    }
    public override void OnNetworkSpawn()
    {
        Debug.Log("D_TickHandler. OnNetworkSpawn");
        StartCoroutine(UpdateTick(2));
    }
    private void HandleValueChanged(int previousValue, int newValue)
    {
        Debug.Log("HandleValueChanged. invokeTickEvent called");
        tickgenerated?.Invoke(previousValue, newValue);
    }
    /// <summary>
    /// This can be called by the server periodically to trigger a tick across server or within ServerRPC
    /// </summary>
    public void invokeTickValueChange()
    {
        if (!IsServer) { return; }
        Debug.Log("invokeTickValueChange");
        tickGenerated.Value += 1;
    }
    IEnumerator UpdateTick(float waitTime)
    {
        if(!IsServer) { yield return null; }
        while (true)
        {
            yield return new WaitForSeconds(waitTime);
            invokeTickValueChange();
        }
    }
}
PitouGames commented 1 year ago

I always read that using constructor in MonoBehaviour (and derived class like NetworkBehaviour) is not recommended and should be avoided. Maybe it plays a role in this issue?