Search Unity

Exception in NetworkBehavior.InitializeVariables()

Discussion in 'Netcode for GameObjects' started by UnkelRambo, Mar 23, 2022.

  1. UnkelRambo

    UnkelRambo

    Joined:
    Oct 26, 2012
    Posts:
    80
    Hello!

    I've upgraded to Netcode 1.0 and am now having this crazy error that I really do not understand at all, hoping somebody here can offer some ideas.

    When I spawn an object with a NetworkBehavior with a single network variable, I get this error:

    NullReferenceException: Object reference not set to an instance of an object
    Unity.Netcode.NetworkBehaviour.InitializeVariables () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Core/NetworkBehaviour.cs:457)
    Unity.Netcode.NetworkBehaviour.InternalOnNetworkSpawn () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Core/NetworkBehaviour.cs:369)
    Unity.Netcode.NetworkObject.InvokeBehaviourNetworkSpawn () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Core/NetworkObject.cs:798)
    Unity.Netcode.NetworkSpawnManager.SpawnNetworkObjectLocallyCommon (Unity.Netcode.NetworkObject networkObject, System.UInt64 networkId, System.Boolean sceneObject, System.Boolean playerObject, System.Nullable`1[T] ownerClientId, System.Boolean destroyWithScene) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Spawning/NetworkSpawnManager.cs:525)
    Unity.Netcode.NetworkSpawnManager.SpawnNetworkObjectLocally (Unity.Netcode.NetworkObject networkObject, System.UInt64 networkId, System.Boolean sceneObject, System.Boolean playerObject, System.Nullable`1[T] ownerClientId, System.Boolean destroyWithScene) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Spawning/NetworkSpawnManager.cs:438)
    Unity.Netcode.NetworkObject.SpawnInternal (System.Boolean destroyWithScene, System.Nullable`1[T] ownerClientId, System.Boolean playerObject) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Core/NetworkObject.cs:476)
    Unity.Netcode.NetworkObject.Spawn (System.Boolean destroyWithScene) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Core/NetworkObject.cs:499)
    Kayyos.Shared.ObjectDefinition.CreateWorldInstance (UnityEngine.Vector3 worldPosition, UnityEngine.Quaternion rotation, System.Boolean destroyWithScene) (at Assets/Kayyos/Scripts/Shared/ObjectDatabase/ObjectDefinition.cs:55)
    Kayyos.Shared.MultiPlayerNetworkController.RegisterPlayer (Kayyos.Shared.NetworkPlayerController controller) (at Assets/Kayyos/Scripts/Shared/Net/Player/MultiPlayerNetworkController.cs:72)
    Kayyos.Shared.MultiPlayerNetworkController.RequestPlayerControllerServerRPC (System.Byte playerIndex) (at Assets/Kayyos/Scripts/Shared/Net/Player/MultiPlayerNetworkController.cs:116)
    Kayyos.Shared.MultiPlayerNetworkController.__rpc_handler_1200881751 (Unity.Netcode.NetworkBehaviour target, Unity.Netcode.FastBufferReader reader, Unity.Netcode.__RpcParams rpcParams) (at <73ea9c94abc5452291b2ea4b834d97ed>:0)
    Unity.Netcode.RpcMessageHelpers.Handle (Unity.Netcode.NetworkContext& context, Unity.Netcode.RpcMetadata& metadata, Unity.Netcode.FastBufferReader& payload, Unity.Netcode.__RpcParams& rpcParams) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Messaging/Messages/RpcMessages.cs:77)
    Rethrow as Exception: Unhandled RPC exception!
    UnityEngine.Debug:LogException(Exception)
    Unity.Netcode.RpcMessageHelpers:Handle(NetworkContext&, RpcMetadata&, FastBufferReader&, __RpcParams&) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Messaging/Messages/RpcMessages.cs:81)
    Unity.Netcode.ServerRpcMessage:Handle(NetworkContext&) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Messaging/Messages/RpcMessages.cs:122)
    Unity.Netcode.NetworkBehaviour:__endSendServerRpc(FastBufferWriter&, UInt32, ServerRpcParams, RpcDelivery) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.6/Runtime/Core/NetworkBehaviour.cs:93)
    Kayyos.Shared.MultiPlayerNetworkController:RequestPlayerControllerServerRPC(Byte) (at Assets/Kayyos/Scripts/Shared/Net/Player/MultiPlayerNetworkController.cs:99)
    Kayyos.Shared.MultiPlayerNetworkController:RequestPlayerController(Int32) (at Assets/Kayyos/Scripts/Shared/Net/Player/MultiPlayerNetworkController.cs:153)
    Kayyos.Shared.MultiPlayerNetworkController:HandleOnPlayerJoined(PlayerInput) (at Assets/Kayyos/Scripts/Shared/Net/Player/MultiPlayerNetworkController.cs:93)
    UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
    UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)

    What's weird is that, stepping through the code, the NetworkVariableFields list is in fact null somehow when InitializeVariables() is called:

    Code (CSharp):
    1.  
    2. internal void InitializeVariables()
    3.         {
    4.             if (m_VarInit)
    5.             {
    6.                 return;
    7.             }
    8.  
    9.             m_VarInit = true;
    10.  
    11.             FieldInfo[] sortedFields = GetFieldInfoForType(GetType());
    12.  
    13.             for (int i = 0; i < sortedFields.Length; i++)
    14.             {
    15.                 Type fieldType = sortedFields[i].FieldType;
    16.  
    17.                 if (fieldType.IsSubclassOf(typeof(NetworkVariableBase)))
    18.                 {
    19.                     var instance = (NetworkVariableBase)sortedFields[i].GetValue(this);
    20.  
    21.                     if (instance == null)
    22.                     {
    23.                         throw new Exception($"{GetType().FullName}.{sortedFields[i].Name} cannot be null. All {nameof(NetworkVariableBase)} instances must be initialized.");
    24.                     }
    25.  
    26.                     instance.Initialize(this);
    27.  
    28.                     var instanceNameProperty = fieldType.GetProperty(nameof(NetworkVariableBase.Name));
    29.                     var sanitizedVariableName = sortedFields[i].Name.Replace("<", string.Empty).Replace(">k__BackingField", string.Empty);
    30.                     instanceNameProperty?.SetValue(instance, sanitizedVariableName);
    31.  
    32.                     NetworkVariableFields.Add(instance); // NetworkVariableFields is NULL here...
    33.                 }
    34.             }
    35. ...
    36.  
    The behavior is very simple, with a single NetworkVariable:


    Code (CSharp):
    1.     public class WorldObjectConceptState : NetworkBehaviour, IConceptStateProvider, IPlayerPossessable
    2.     {
    3.         public NetworkVariable<NetworkDataEntityRef> definition = new NetworkVariable<NetworkDataEntityRef>();
    4. ...
    And here's the ONLY weird part, NetworkDataEntityRef is a struct I'm using to simplify lookup into an object database I've defined:


    Code (CSharp):
    1. public struct NetworkDataEntityRef : INetworkSerializable
    2.     {
    3.         private uint id;
    4.  
    5.         public DataEntity Entity
    6.         {
    7.             get
    8.             {
    9.                 var db = Vault.Data as TagSearchableDatabase;
    10.                 return db.GetEntityByID<DataEntity>(id);
    11.             }
    12.         }
    13.  
    14.         public T EntityAs<T>() where T : DataEntity
    15.         {
    16.             return Entity as T;
    17.         }
    18.  
    19.         public NetworkDataEntityRef(DataEntity entity)
    20.         {
    21.             id = entity.ID;
    22.         }
    23.  
    24.         public static implicit operator NetworkDataEntityRef(DataEntity entity)
    25.         {
    26.             return new NetworkDataEntityRef(entity);
    27.         }
    28.  
    29.         public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    30.         {
    31.             serializer.SerializeValue(ref id);
    32.         }
    33.     }
    Removing that network variable, however, still yields the same error.

    The flow is essentially this:
    1. The host creates the MultiplayerNetworkController as the PlayerObject.
    2. When input is detected, a RequestPlayerControllerServerRPC is sent where the server creates a new NetworkPlayerController object and calls RegisterPlayer().
    3. As a hack for testing, inside RegisterPlayer() I spawn an object from my database (via CreateWorldInstance()) and THAT object is causing this error.

    This whole setup and flow worked for months with MLAPI, and WEIRDLY it worked fine yesterday. I've restarted Unity, my computer, nuked the Library folder, etc.

    If I remove the WorldObjectConceptState (the NetworkBehavior I started working on this morning as part of a refactor of existing functionality) from the object that gets spawned, everything is peachy and no error occurs. Here's the offender:

    Code (CSharp):
    1.     public class WorldObjectConceptState : NetworkBehaviour, IConceptStateProvider, IPlayerPossessable
    2.     {
    3.         public NetworkVariable<NetworkDataEntityRef> definition = new NetworkVariable<NetworkDataEntityRef>();
    4.  
    5.         private List<IFixedTickableConcept> fixedTickableConcepts = new List<IFixedTickableConcept>();
    6.         private List<ITickableConcept> tickableConcepts = new List<ITickableConcept>();
    7.  
    8.         public WorldObjectConceptState(CharacterController characterController)
    9.         {
    10.             CharacterController = characterController;
    11.         }
    12.  
    13.         public NetworkPlayerController PossessingPlayer { get; private set; }
    14.  
    15.         /// <summary>
    16.         ///     Cached Components
    17.         /// </summary>
    18.         public CharacterController CharacterController { get; private set; }
    19.         public Rigidbody Rigidbody { get; private set; }
    20.         public Animator Animator { get; private set; }
    21.  
    22.         public ObjectDefinition Definition
    23.         {
    24.             get => definition.Value.EntityAs<ObjectDefinition>();
    25.             set => definition.Value = value;
    26.         }
    27.  
    28.         public bool CanPossess(NetworkPlayerController controller)
    29.         {
    30.             return true;
    31.         }
    32.  
    33.         public void Possess(NetworkPlayerController controller)
    34.         {
    35.             PossessingPlayer = controller;
    36.             Debug.Log($"Object possessed: {name}->{Definition}");
    37.         }
    38.  
    39.         public bool CanUnpossess()
    40.         {
    41.             return true;
    42.         }
    43.  
    44.         public void Unpossess()
    45.         {
    46.             PossessingPlayer = null;
    47.         }
    48.  
    49.         public override void OnNetworkSpawn()
    50.         {
    51.             base.OnNetworkSpawn();
    52.  
    53.             Debug.Log($"Object Spawned: {Definition}");
    54.             if (!Definition)
    55.             {
    56.                 Debug.LogError("Definition isn't set on spawn, something went horribly wrong...");
    57.                 return;
    58.             }
    59.  
    60.             foreach (var concept in Definition.Concepts)
    61.             {
    62.                 if (concept is IFixedTickableConcept fixedTickableConcept)
    63.                     fixedTickableConcepts.Add(fixedTickableConcept);
    64.  
    65.                 if (concept is ITickableConcept tickableConcept)
    66.                     tickableConcepts.Add(tickableConcept);
    67.             }
    68.         }
    69.  
    70.         public override void OnNetworkDespawn()
    71.         {
    72.             base.OnNetworkDespawn();
    73.         }
    74.  
    75.         protected void Awake()
    76.         {
    77.             definition.OnValueChanged += (value, newValue) =>
    78.             {
    79.                 if (IsClient)
    80.                     Debug.Log($"Client Definition changed: {Definition}");
    81.                 if (IsServer)
    82.                     Debug.Log($"Server Definition changed: {Definition}");
    83.             };
    84.  
    85.             // Cache components
    86.             CharacterController ??= GetComponent<CharacterController>();
    87.             Rigidbody ??= GetComponent<Rigidbody>();
    88.             Animator ??= GetComponent<Animator>();
    89.         }
    90.     }
    Somewhere in here, I've touched something in a bad way. Halp me UnityWanKenobi, you're my only hope!
     
    brainwipe likes this.
  2. UnkelRambo

    UnkelRambo

    Joined:
    Oct 26, 2012
    Posts:
    80
    Oh good lord, staring at this for an hour and it didn't click that ReSharper did a cool thing and created a constructor for me, which broke literally everything.

    This one's a big "my bad", carry on but leaving this one up for posterity lol
     
    Derzsky, brainwipe and S4Slean like this.
  3. BurnEmDown

    BurnEmDown

    Joined:
    Dec 29, 2019
    Posts:
    28
    Hi, I'm also running into a similar issue when I try to spawn a networkbehavior.
    I tried adding an initializer to the constructor for the NetworkVariable, using
    Code (CSharp):
    1. ??=
    as I initialize it on Awake() as well.

    Here is the error message stack:
    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. Unity.Netcode.NetworkBehaviour.InitializeVariables () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviour.cs:543)
    3. Unity.Netcode.NetworkBehaviour.InternalOnNetworkSpawn () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviour.cs:437)
    4. Unity.Netcode.NetworkObject.InvokeBehaviourNetworkSpawn () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkObject.cs:817)
    5. Unity.Netcode.NetworkSpawnManager.SpawnNetworkObjectLocallyCommon (Unity.Netcode.NetworkObject networkObject, System.UInt64 networkId, System.Boolean sceneObject, System.Boolean playerObject, System.UInt64 ownerClientId, System.Boolean destroyWithScene) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Spawning/NetworkSpawnManager.cs:552)
    6. Unity.Netcode.NetworkSpawnManager.SpawnNetworkObjectLocally (Unity.Netcode.NetworkObject networkObject, System.UInt64 networkId, System.Boolean sceneObject, System.Boolean playerObject, System.UInt64 ownerClientId, System.Boolean destroyWithScene) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Spawning/NetworkSpawnManager.cs:453)
    7. Unity.Netcode.NetworkObject.SpawnInternal (System.Boolean destroyWithScene, System.UInt64 ownerClientId, System.Boolean playerObject) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkObject.cs:466)
    8. Unity.Netcode.NetworkObject.Spawn (System.Boolean destroyWithScene) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkObject.cs:483)
    9. SpawnerController.SpawnCavArcher (HexCell cell, Enums+Faction playerFaction) (at Assets/Scripts/SpawnerController.cs:51)
    10. HexMapEditor.CreateHorseArcher (Enums+Faction playerFaction) (at Assets/Scripts/Hex/HexMapEditor.cs:147)
    11. HexMapEditor.Update () (at Assets/Scripts/Hex/HexMapEditor.cs:62)
    I can see with the debugger that the NetworkVariable is getting initialized and isn't null at the end of Awake() and that in
    Unity.Netcode.NetworkBehaviour.InitializeVariables ()
    the NetworkVariableFields is null.

    Also, when I try to make a change to the NetworkVariable by moving the unit, the unit is moved properly but I get non-stop errors with this stack:
    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. Unity.Netcode.NetworkBehaviour.PreNetworkVariableWrite () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviour.cs:575)
    3. Unity.Netcode.NetworkBehaviour.PreVariableUpdate () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviour.cs:597)
    4. Unity.Netcode.NetworkBehaviourUpdater.NetworkBehaviourUpdate (Unity.Netcode.NetworkManager networkManager) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviourUpdater.cs:35)
    5. Unity.Netcode.NetworkManager.OnNetworkManagerTick () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkManager.cs:1604)
    6. Unity.Netcode.NetworkTickSystem.UpdateTick (System.Double localTimeSec, System.Double serverTimeSec) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Timing/NetworkTickSystem.cs:102)
    7. Unity.Netcode.NetworkManager.OnNetworkPreUpdate () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkManager.cs:1568)
    8. Unity.Netcode.NetworkManager.NetworkUpdate (Unity.Netcode.NetworkUpdateStage updateStage) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkManager.cs:1476)
    9. Unity.Netcode.NetworkUpdateLoop.RunNetworkUpdateStage (Unity.Netcode.NetworkUpdateStage updateStage) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkUpdateLoop.cs:185)
    10. Unity.Netcode.NetworkUpdateLoop+NetworkPreUpdate+<>c.<CreateLoopSystem>b__0_0 () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkUpdateLoop.cs:232)
    Using debugger I can see on Unity.Netcode.NetworkBehaviour.PreNetworkVariableWrite () that
    NetworkVariableIndexesToReset is null.
     
  4. BurnEmDown

    BurnEmDown

    Joined:
    Dec 29, 2019
    Posts:
    28
    Could you share what you did to solve this issue?
     
  5. UnkelRambo

    UnkelRambo

    Joined:
    Oct 26, 2012
    Posts:
    80
    The key was this constructor:


    Code (CSharp):
    1.         public WorldObjectConceptState(CharacterController characterController)
    2.         {
    3.             CharacterController = characterController;
    4.         }
    5.  
    I don't remember the details, but deleting this handily auto-generated constructor fixed the issue for me IIRC.
     
  6. BurnEmDown

    BurnEmDown

    Joined:
    Dec 29, 2019
    Posts:
    28
    I see, unfortunately for me I don't think the issue is constructor-related, I'm gonna have to keep digging to find the solution
     
    Last edited: Aug 31, 2022
  7. BurnEmDown

    BurnEmDown

    Joined:
    Dec 29, 2019
    Posts:
    28
    I've been playing around trying different stuff, I now tried to first instantiate and then spawn a different object, and I think I'm running into a similar issue with the constructor. When I try to spawn the object, I get this warning message:


    Code (CSharp):
    1. You are trying to create a MonoBehaviour using the 'new' keyword.  This is not allowed.  MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
    2. UnityEngine.MonoBehaviour:.ctor ()
    3. Unity.Netcode.NetworkBehaviour:.ctor () (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviour.cs:606)
    4. HexGridChunk:.ctor () (at Assets/Scripts/Hex/HexGridChunk.cs:904)
    5. System.Activator:CreateInstance<HexGridChunk> ()
    6. Unity.Netcode.FastBufferReader:ReadNetworkSerializable<HexGridChunk> (HexGridChunk&) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Serialization/FastBufferReader.cs:443)
    7. Unity.Netcode.FastBufferReader:ReadValueSafe<HexGridChunk> (HexGridChunk&,Unity.Netcode.FastBufferWriter/ForNetworkSerializable) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Serialization/FastBufferReader.cs:776)
    8. SpawnerController:__rpc_handler_2692164904 (Unity.Netcode.NetworkBehaviour,Unity.Netcode.FastBufferReader,Unity.Netcode.__RpcParams)
    9. Unity.Netcode.RpcMessageHelpers:Handle (Unity.Netcode.NetworkContext&,Unity.Netcode.RpcMetadata&,Unity.Netcode.FastBufferReader&,Unity.Netcode.__RpcParams&) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Messaging/Messages/RpcMessages.cs:77)
    10. Unity.Netcode.ServerRpcMessage:Handle (Unity.Netcode.NetworkContext&) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Messaging/Messages/RpcMessages.cs:122)
    11. Unity.Netcode.NetworkBehaviour:__endSendServerRpc (Unity.Netcode.FastBufferWriter&,uint,Unity.Netcode.ServerRpcParams,Unity.Netcode.RpcDelivery) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.1/Runtime/Core/NetworkBehaviour.cs:93)
    12. SpawnerController:SpawnChunkServerRpc (HexGridChunk) (at Assets/Scripts/SpawnerController.cs:58)
    13. HexGrid:CreateChunks () (at Assets/Scripts/Hex/HexGrid.cs:306)
    14. NetworkUI/<>c:<Start>b__8_4 () (at Assets/Scripts/NetworkUI.cs:89)
    15. UnityEngine.EventSystems.EventSystem:Update ()
    The object is instantiated on the host but not on the client.
    At first there wasn't any constructor for the HexGridChunk object which I'm trying to spawn, I tried to add one now but I get the same error.
     
  8. BurnEmDown

    BurnEmDown

    Joined:
    Dec 29, 2019
    Posts:
    28
    I continued to play around with it and found that if I instantiate the object inside the ServerRpc method that will spawn it as well, the constructor isn't called. I do run into another issue which I've described here, but at least this unnecessary call to the constructor is solved

    https://forum.unity.com/threads/serverrpc-called-twice.1330053/