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.14k stars 433 forks source link

Modifications on NetworkVariables on in-scene placed NetworkObjects are reset to defaults #2334

Open fernando-cortez opened 1 year ago

fernando-cortez commented 1 year ago

Description

One cannot modify NetworkVariables on in-scene placed NetworkObjects. When one does, you get the following warning message:

NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. Are you modifying a NetworkVariable before the NetworkObject is spawned?
UnityEngine.Debug:LogWarning (object)
Unity.Netcode.NetworkVariableBase:SetDirty (bool) (at Library/PackageCache/com.unity.netcode.gameobjects@1.1.0/Runtime/NetworkVariable/NetworkVariableBase.cs:88)
Unity.Netcode.NetworkVariable`1<IngredientType>:Set (IngredientType) (at Library/PackageCache/com.unity.netcode.gameobjects@1.1.0/Runtime/NetworkVariable/NetworkVariable.cs:74)
Unity.Netcode.NetworkVariable`1<IngredientType>:set_Value (IngredientType) (at Library/PackageCache/com.unity.netcode.gameobjects@1.1.0/Runtime/NetworkVariable/NetworkVariable.cs:63)
Unity.Netcode.Editor.NetworkBehaviourEditor:RenderNetworkVariableValueType<IngredientType> (int) (at Library/PackageCache/com.unity.netcode.gameobjects@1.1.0/Editor/NetworkBehaviourEditor.cs:145)
System.Reflection.MethodBase:Invoke (object,object[])
Unity.Netcode.Editor.NetworkBehaviourEditor:RenderNetworkVariable (int) (at Library/PackageCache/com.unity.netcode.gameobjects@1.1.0/Editor/NetworkBehaviourEditor.cs:73)
Unity.Netcode.Editor.NetworkBehaviourEditor:OnInspectorGUI () (at Library/PackageCache/com.unity.netcode.gameobjects@1.1.0/Editor/NetworkBehaviourEditor.cs:176)
UnityEditor.EditorGUI/PopupCallbackInfo:SetEnumValueDelegate (object,string[],int)

and the NetworkVariable is reset to the default value.

Reproduce Steps

  1. Go to ClientDriven Bitesize sample commit highlighting the issue
  2. Open the Bootstrap scene and try to modify the in-scene placed Ingredient IngredientType (NetworkVariable).
  3. See the warning message and the NetworkVariable being reset.

Actual Outcome

NetworkVariables on in-scene placed NetworkObject was reset.

Expected Outcome

NetworkVariables on in-scene placed NetworkObject should not be reset and should be saved in the scene.

Screenshots

If applicable, add screenshots to help explain your problem.

Environment

Additional Context

Add any other context about the problem here. Logs, code snippets would be useful here but please also consider attaching a minimal Unity project that reproduces the issue.

ashwinimurt commented 1 year ago

MTT-5198

NoelStephensUnity commented 1 year ago

@fernando-cortez With in-scene placed NetworkObjects, you can use the awake method to accomplish this type of functionality.

using System;
using Unity.Netcode;
using UnityEngine;

public class ServerIngredient : ServerObjectWithIngredientType
{
}

public enum IngredientType
{
    Red,
    Blue,
    Purple,
    MAX // should be always last
}

public class ServerObjectWithIngredientType : NetworkBehaviour
{
    // NOTE: this is a workaround on an issue NGO-side. NetworkVariables should be able to be set pre-spawn.
    [SerializeField]
    private IngredientType m_StartingIngredientType;

    private NetworkVariable<IngredientType> m_CurrentIngredientType;

    public event Action IngredientDespawned;

    private void Awake()
    {
        m_CurrentIngredientType = new NetworkVariable<IngredientType>(m_StartingIngredientType);
    }

    public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();
        if (!IsServer)
        {
            enabled = false;
            return;
        }

        Debug.Log($"Current Ingredient Type: {m_CurrentIngredientType.Value}");
    }

    public override void OnNetworkDespawn()
    {
        IngredientDespawned?.Invoke();
    }
}

Replace the ClientDriven bite sample's ServerIngredient file with the above adjustments. It just instantiates the NetworkVariable in Awake based on the m_StartingIngredientType property's value.

The NetworkVariable documentation provides an order of operations table (dynamically spawned vs in-scene placed). For both dynamically spawned and in-scene placed NetworkObjects, you can instantiate a NetworkVariable within the Awake method and assign the initial value based on a serialized property's value.

NoelStephensUnity commented 1 year ago

Side note: Since this type of functionality can be achieved in NGO, I am going to mark this as a feature request. I do think we can make an adjustment that would allow you to accomplish this without having to instantiate the NetworkVariable within the Awake method.