Search Unity

Question How do I NetworkSerialize a List in INetworkSerializable?

Discussion in 'Netcode for GameObjects' started by CptMarvel21, Aug 26, 2022.

  1. CptMarvel21

    CptMarvel21

    Joined:
    Sep 18, 2021
    Posts:
    12
    I have a struct that has all the card data I want to serialize. The strings and ints work perfectly, but when I try to add a List of ints, the NetworkSerialize function says it cant convert from ref list to ref string
     
  2. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    You cannot (directly) serialize a list. You can however serialize an array of strings, so if you add an intermediate ToArray step when writing (and transform back when reading) it should work.
     
  3. CptMarvel21

    CptMarvel21

    Joined:
    Sep 18, 2021
    Posts:
    12
    I tried doing this but im getting errors that say my CardData struct and any levels of nesting in it must be a non-nullable type.
     
  4. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    Can you post the relevant bits of your code?
     
  5. CptMarvel21

    CptMarvel21

    Joined:
    Sep 18, 2021
    Posts:
    12
    Using the documentation for reference, this is what i came up with
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Netcode;
    5. using System;
    6. using Unity.Collections;
    7.  
    8. public struct CardData : INetworkSerializable, IEquatable<CardData>
    9. {
    10.    
    11.     public int DamageAmount;
    12.     public List<int> EffectIndex;
    13.  
    14.     public CardData(int damageAmount, List<int> effectIndex)
    15.     {
    16.         DamageAmount = damageAmount;
    17.         EffectIndex = effectIndex;
    18.     }
    19.  
    20.     public bool Equals(CardData other)
    21.     {
    22.         return DamageAmount == other.DamageAmount &&
    23.                 EffectIndex == other.EffectIndex;
    24.     }
    25.  
    26.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    27.     {
    28.         serializer.SerializeValue(ref DamageAmount);
    29.  
    30.         int length = 0;
    31.         int[] Array = EffectIndex.ToArray();
    32.         if (!serializer.IsReader)
    33.         {
    34.             length = Array.Length;
    35.         }
    36.  
    37.         serializer.SerializeValue(ref length);
    38.  
    39.         for (int n = 0; n < length; ++n)
    40.         {
    41.             serializer.SerializeValue(ref Array[n]);
    42.         }
    43.     }
    44. }
    45.  
     
  6. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    This is in the right direction, but notice that line 31 fails when reading because EffectIndex will be empty. Also, you don’t convert back from Array to EffectIndex when reading so the array will never be filled.

    I can’t test this right now (on my phone), but I suspect something like this should work:


    Code (CSharp):
    1.         int length = 0;
    2.         int[] Array;
    3.         if (!serializer.IsReader)
    4.         {
    5.             Array = EffectIndex.ToArray();
    6.             length = Array.Length;
    7.         }
    8.         serializer.SerializeValue(ref length);
    9.  
    10.         if (serializer.IsReader)
    11.         {
    12.             Array = new int[length];
    13.        }
    14.         for (int n = 0; n < length; ++n)
    15.         {
    16.             serializer.SerializeValue(ref Array[n]);
    17.         }
    18.  
    19.         if (serializer.IsReader)
    20.         {
    21.             EffectIndex = Array.ToList();
    22.        }
     
    Last edited: Aug 28, 2022
  7. CptMarvel21

    CptMarvel21

    Joined:
    Sep 18, 2021
    Posts:
    12
    On your line 16, I get a "Use of unassigned local variable 'Array' " error. Below is my fix which I'm hoping is the right way. Although there are no more errors on my IDE, I still get the following error.
    "The type 'CardData' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'NetworkVariable<T>"
    Code (CSharp):
    1. int length = 0;
    2.         int[] Array;
    3.         if (!serializer.IsReader)
    4.         {
    5.             Array = EffectIndex.ToArray();
    6.             length = Array.Length;
    7.         }
    8.         else
    9.         {
    10.             Array = new int[length];
    11.         }
    12.         serializer.SerializeValue(ref length);
    13.  
    14.         for (int n = 0; n < length; ++n)
    15.         {
    16.             serializer.SerializeValue(ref Array[n]);
    17.         }
    18.  
    19.         if (serializer.IsReader)
    20.         {
    21.             EffectIndex = Array.ToList();
    22.         }
     
  8. unity_E8A9B4215B535F4278D8

    unity_E8A9B4215B535F4278D8

    Joined:
    Dec 9, 2022
    Posts:
    1
    Goodmorning,
    I have the same problem and I founded your solution but, when I try to change my data (from server to client) I recive the error "NullReferenceException: Object reference not set to an instance of an object".
    Can you help me with this problem?
    Actually i'm using the following revision
    Unity: 2022.3.5f1
    UnityTransport:1.3.4
    UnityNetcode for GameObjects 1.5.2


    Thanks in advance
     
  9. rogerwang86

    rogerwang86

    Joined:
    Jun 18, 2020
    Posts:
    1
    To those who stuck on here (like me before), here is the final workable code:

    Code (CSharp):
    1.         int length = 0;
    2.         int[] Array;
    3.         if (serializer.IsWriter)
    4.         {
    5.             Array = EffectIndex.ToArray();
    6.             length = Array.Length;
    7.         }
    8.         else
    9.         {
    10.             Array = new int[length];
    11.         }
    12.         serializer.SerializeValue(ref length);
    13.         serializer.SerializeValue(ref Array);
    14.  
    15.         if (serializer.IsReader)
    16.         {
    17.             EffectIndex = Array.ToList();
    18.         }