Search Unity

Question NetworkList exploding with custom struct that works with NetworkVariable

Discussion in 'Netcode for GameObjects' started by hoesterey, Jan 17, 2022.

  1. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    I'm absolutely stuck here. I have a class that doesn't serialize and transfer across the network in a Network Variable, though I get no errors. But when used in a NetworkList it produces the following error:
    UnityException: EditorPrefsGetInt is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour 'StatusBehavior' on game object 'PlayerNetworkedGame'.

    //No Error
    private NetworkVariable<StatusEffect> m_Status1 = new NetworkVariable<StatusEffect>();
    //Above Error.
    private NetworkList<StatusEffect> m_Status = new NetworkList<StatusEffect>();


    See the struct below.
    Code (CSharp):
    1. [Serializable]
    2.     public partial struct StatusEffect: INetworkSerializable, IEquatable<StatusEffect>
    3.     {
    4.  
    5.         public int m_Hash; //hash be faster then string
    6.         public double m_EndTime;//server time or round time depending on combat type.
    7.         public int m_Level;
    8.         public ulong m_Owner;  //client ID
    9.         public string m_DisplayName => data.DisplayName;
    10.         public string m_Discription => data.Description;
    11.         public string name => data.name;
    12.         public Sprite m_Sprite => data.Sprite;
    13.         public StatusEffectData.Statuses m_Status => data.Status;
    14.         public GameplayDefs.Dice[] m_EffectDice => data.EffectDice;
    15.         public int m_EffectValue => data.EffectValue;
    16.         public StatusEffectData.SaveTypes m_SaveType => data.SaveType;
    17.         public StatusEffectData.SaveFrequencys m_SaveFrequency => data.SaveFrequency;
    18.         public StatusEffectData.ApplyFrequencys m_ApplyFrequency => data.ApplyFrequency;
    19.         public int m_SaveValue => data.SaveValue;
    20.  
    21.         public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    22.         {
    23.             serializer.SerializeValue(ref m_Hash);
    24.             serializer.SerializeValue(ref m_EndTime);
    25.             serializer.SerializeValue(ref m_Level);
    26.             serializer.SerializeValue(ref m_Owner);
    27.         }
    28.  
    29.         public bool Equals(StatusEffect other)
    30.         {
    31.             return m_Hash .Equals(other.m_Hash) && m_EndTime.Equals(other.m_EndTime) && m_Level.Equals(other.m_Level) && m_Owner.Equals(other.m_Owner);
    32.         }
    33.  
    34.         public StatusEffect(StatusEffectData data, ulong ownerClientID,  int level, int durationModifier)
    35.         {
    36.             m_Owner = ownerClientID;
    37.             m_Hash = data.name.GetStableHashCode();
    38.             m_Level = level;
    39.             double gameTime = ZoneInstance.Instance.GetGameTime();
    40.             m_EndTime = data.Duration + gameTime;//TODO add round or network time
    41.         }
    42.  
    43.         public StatusEffectData data
    44.         {
    45.             get
    46.             {
    47.                 // show a useful error message if the key can't be found
    48.                 // note: ScriptableSkill.OnValidate 'is in resource folder' check
    49.                 //       causes Unity SendMessage warnings and false positives.
    50.                 //       this solution is a lot better.
    51.                 if (!StatusEffectLookup.All.ContainsKey(m_Hash))
    52.                     throw new KeyNotFoundException("There is no ScriptableSkill with hash=" + m_Hash + ". Make sure that all ScriptableSkills are in the Resources folder so they are loaded properly.");
    53.                 return (StatusEffectData)StatusEffectLookup.All[m_Hash];
    54.             }
    55.         }
    56. }
     
    Last edited: Jan 17, 2022
  2. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    664
    daxiongmao likes this.
  3. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659

    Turns out I can't get anything custom to serialize with NetworkVariables either. Simplest test ever (even tried not declaring till awake). Simplest test I can think to make does not work :(

    Displays as 10 on the host/server and 0 on the client.

    //Class to seralize
    Code (CSharp):
    1.  
    2. using Unity.Netcode;
    3.  
    4.  
    5. public struct TestNet : INetworkSerializable
    6. {
    7.     public int m_Hash;
    8.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    9.     {
    10.         serializer.SerializeValue(ref m_Hash);
    11.     }
    12. }
    13.  
    //Class that should display numbers on the client.
    private NetworkVariable<TestNet> m_Status1;
    Code (CSharp):
    1. private void Awake()
    2.         {
    3.              m_Status1 = new NetworkVariable<TestNet>();
    4.         }
    5.  
    6. bool b = false;
    7. private void Update()
    8.         {
    9.    
    10.             if(!b && IsServer)
    11.             {
    12.                 TestNet t = new TestNet();
    13.                 t.m_Hash = 10;
    14.                 m_Status1.Value = t
    15.                 Debug.LogError("Server created test");
    16.                 b = true;
    17.            
    18.             }
    19.             if(IsClient)
    20.             {
    21.                 Debug.LogError(m_Status1.Value.m_Hash);
    22.             }
    23.             else
    24.             {
    25.                 Debug.LogError("?");
    26.             }
    27.         }
    28.  
     
  4. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    I got the simple example above to work by moving the component off the player objects...but that makes no sense :(
     
  5. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    Ok,
    So. You were correct. moving the =new to "Awake" (wow that is dirty) I got the test and my original example working! It seamed that ANYWHERE in the project I defined a net list defined inline seamed to silently nuke the whole project so I had to fix that everywhere before it worked.

    Also random question. Anyone know where I can get NetworkDictionary? I'm not seeing it in the library anymore. If I have working NetworkVars/Lists/Dictionaries/ and RPCS its all I need to develop. This all should be stable in the 3-5 years we have to finish the game?
     
  6. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    664
    NetworkDictionary was removed and there's no future plans to support them as far as I know.
     
  7. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    That is sad. I can work around lack of dictionaries but they are great for stat and resource management.

    Cant work around Lack of lists though so happy those are working.