Search Unity

Resolved Sending a list/array of NetworkObjects over the network

Discussion in 'Netcode for GameObjects' started by Punnet_Red, Jan 13, 2022.

  1. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    Hello,

    In my project, I am hoping to send a list of NetworkObjects from the client to the server, and vice versa. I was wondering if anyone could help point me in the right direction on how best to achieve this?

    What I've tried to do so far is to convert the list of NetworkObjects into an array, and then try send the array of NetworkObjects (e.g. Location[], where Location is a NetworkObject) through an RPC, described below:

    Code (CSharp):
    1.  
    2. private List<Location> movementQueue = new List<Location>();
    3.  
    4. NetworkObjectReference[] toSend = new NetworkObjectReference[movementQueue.Count];
    5.  
    6. for (int i = 0; i < movementQueue.Count; i++) {
    7.  
    8.     toSend[i] = movementQueue[i].NetworkObject;
    9.  
    10. }
    11.  
    12. SendMovementQueueServerRpc(toSend);
    13.  
    Code (CSharp):
    1.  
    2.  
    3. private List<Location> movementQueue = new List<Location>();
    4.  
    5. [ServerRpc]
    6. public void SendMovementQueueServerRpc(NetworkObjectReference[] movementList) {
    7.  
    8.     foreach (NetworkObjectReference moveRef in movementList) {
    9.  
    10.         if (moveRef.TryGet(out NetworkObject location)) {
    11.  
    12.             movementQueue.Add(location.GetComponent<Location>());
    13.  
    14.         }
    15.  
    16.     }
    17.  
    18. }
    19.  
    This throws an error: "NullReferenceException: Object reference not set to an instance of an object"

    Happy to find if a NetworkList is better suited for my situation - hoping for any guidance!
     
    Last edited: Jan 13, 2022
  2. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    660
    This appears to work both ways, at least in my crude testing using NetworkBehaviourReference. Do the Location network objects already exist on both server and client?
     
  3. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    Hello, thanks for giving it try - yeah, the Location network objects exist on both sides. Okay, if this is working for you, maybe I have something else that is messing it up.

    I will continue testing, and will update soon (hopefully).
     
  4. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    I should have included this in the original post, but here is some more of the error messages:

    Unity.Netcode.FastBufferWriter.WriteNetworkSerializable[T] (T& value) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.3/Runtime/Serialization/FastBufferWriter.cs:421)
    Unity.Netcode.FastBufferWriter.WriteNetworkSerializable[T] (Unity.Netcode.INetworkSerializable[] array, System.Int32 count, System.Int32 offset) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.3/Runtime/Serialization/FastBufferWriter.cs:437)
     
  5. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    660
    What line is throwing the error, I'm assuming the value in the array is null. Has this ever worked?

    It may help to know what you're using this list for as it may be preferable to use a NetworkList rather than sending the references over an RPC.
     
  6. luke-unity

    luke-unity

    Joined:
    Sep 30, 2020
    Posts:
    306
    The stacktrace you posted isn't the full error message. The first lines are missing which indicate what error occurred. Providing them would make it easier to spot what's wrong.
     
  7. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    Hi everyone, thanks again for your help so far.

    This is the full error message:

    NullReferenceException: Object reference not set to an instance of an object
    Unity.Netcode.FastBufferWriter.WriteNetworkSerializable[T] (T& value) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.3/Runtime/Serialization/FastBufferWriter.cs:421)
    Unity.Netcode.FastBufferWriter.WriteNetworkSerializable[T] (Unity.Netcode.INetworkSerializable[] array, System.Int32 count, System.Int32 offset) (at Library/PackageCache/com.unity.netcode.gameobjects@1.0.0-pre.3/Runtime/Serialization/FastBufferWriter.cs:437)
    Player.SendMovementQueueServerRpc (Unity.Netcode.NetworkObjectReference[] movementList) (at Assets/Scripts/Game/Player.cs:487)
    GameManager.ReadyforMovementExecution () (at Assets/Scripts/Game/GameManager.cs:451)
    UIMovement.<Start>b__2_0 () (at Assets/Scripts/Game/UIMovement.cs:14)
    UnityEngine.Events.InvokableCall.Invoke () (at <85997bd0a5b743419f7356a48e26c8bb>:0)
    UnityEngine.Events.UnityEvent.Invoke () (at <85997bd0a5b743419f7356a48e26c8bb>:0)
    UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
    UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
    UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
    UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
    UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:501)

    The error occurs at whatever the first line of the SendMovementQueueServerRpc(NetworkObjectReference[] movementList) function is, e.g. in the full error message above, the error is thrown at a Debug message that I am using for testing purposes.

    Code (CSharp):
    1.  
    2. [ServerRpc]
    3. public void SendMovementQueueServerRpc(NetworkObjectReference[] movementList) {
    4.  
    5.     Debug.Log("This is a test message.");
    6.  
    7.     foreach (NetworkObjectReference moveRef in movementList) {
    8.  
    9.         if (moveRef.TryGet(out NetworkObject location)) {
    10.  
    11.             movementQueue.Add(location.GetComponent<Location>());
    12.  
    13.         }
    14.  
    15.     }
    16.  
    17. }
    18.  
    The Debug message does not get printed on either side of the network.
     
    Last edited: Jan 15, 2022
  8. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    In reply to cerestorm's question on what I am using it for, I am building a turn-based game, where a player moves through various locations in one turn before arriving at their final destination, e.g. forward one square and then left one square.
    When a client player has committed their moves for a turn, I would like the list of their moves to be sent to the server, so that the server can handle the movement.

    If I were to use a NetworkList, would it be a NetworkList<NetworkObjectReference>?
     
  9. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    If I force the "toSend's" value to be null i.e. by doing
    Code (CSharp):
    1. toSend = null;
    the line before,
    Code (CSharp):
    1. SendMovementQueueServerRpc(toSend);
    the RPC 'works' without issue. The Debug message mentioned above gets printed on the server side.

    Otherwise, this has never worked.
     
  10. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    660
    I tried testing with your code and I'm not getting any errors. I would have expected you to be getting a RPC exception once it enters that domain, at least that's what I'm used to seeing. Perhaps there's something about the Location class it doesn't like, you could share that code. I can really only speculate at this point though, if you don't mind sharing your project or at least enough code to produce the error I can take a look at it.

    From what you've described I'm working on something similar, although perhaps not similar enough to be useful. Players can move 'armies' across a map of locations in the same way, but when they click a location it's the server that creates the path and sends/spawns it on the clients. Then the player can elect to move that army along the path. The moving does happen during the turn though, rather than at the end, with all players taking their turns simultaneously. In your case a RPC might be the best way to go.
     
  11. Punnet_Red

    Punnet_Red

    Joined:
    Mar 7, 2020
    Posts:
    8
    I found the issue - I had not updated Netcode for GameObjects to the latest version (1.0.0-pre.4).

    I realised when I came across this on the Netcode Github: https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/pull/1402

    Thanks so much for your time, cerestorm and luke-unity - thanks cerestorm in particular for sharing how you've implemented something similar to what I am doing :D All the best with your project - sounds interesting to me!
     
    UnityGio and cerestorm like this.