Search Unity

Third Party How to sync a custom class containing a list. (Mirror Networking)

Discussion in 'Multiplayer' started by ForkyTheEditor, Feb 20, 2021.

  1. ForkyTheEditor

    ForkyTheEditor

    Joined:
    May 29, 2016
    Posts:
    1
    Hello!

    I've been working on a Character Stats system lately and I can't for the life of me figure out the best way to sync these stats.
    Code (CSharp):
    1. [System.Serializable]
    2. public class Stat
    3. {
    4.    
    5.     [SerializeField]
    6.     private int baseValue;
    7.  
    8.     [SerializeField]
    9.     private List<int> additiveModifiers = new List<int>();
    10.  
    11.     //Method getters and setters as opposed to properties because Unity can't render properties in Inspector
    12.     public int GetBaseValue()
    13.     {
    14.         return baseValue;
    15.     }
    16.  
    17.     public void SetBaseValue(int value)
    18.     {
    19.         baseValue = value;
    20.     }
    21. }
    Code (CSharp):
    1. public class CharacterStatsComponent : NetworkBehaviour
    2. {
    3.     //TODO: Find a method to sync all the stats across all the clients
    4.    
    5.    
    6.     [SerializeField]
    7.     protected Stat _currentHealth;
    8.     [SerializeField]
    9.     protected Stat _maxHealth;
    10.     [SerializeField]
    11.     protected Teams _team;
    12.  
    13.     [SerializeField]
    14.     protected Stat _attackTime;
    15.     [SerializeField]
    16.     protected Stat _attackDamage;
    17.  
    18.     protected Attackable attackableComponent;
    19. }
    20.  
    There are the two basic classes that I am using. I tried using SyncVar on the Stat fields but it doesn't work (it only works for baseValue and ONLY if it's public.

    I tried using SyncListInt instead of List inside Stat but again, no luck. My guess is it's because it's not a NetworkBehaviour class so it has no idea what the NetId is. Any ideas?
     
    akuno likes this.
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Personally I would add serialize/deserialize methods to the Stat class that convert a Stat object to a byte array. Then I'd send that byte array, probably in a ClientRPC. Use bitconverter to convert the int type variables back and forth to byte arrays. Send the count of the list ahead of the data in the list. But I'm not using mirror, so don't know if the creator added a better way than Unet had.
     
    ForkyTheEditor likes this.
  3. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'm referring to something like this. Just send the returned byte array from Serialize() over a ClientRPC. On the other end, create a new Stat and call Deserialize, passing it the received byte array. Didn't test the code, so hopefully no bugs, just wrote it in the forum. But you get the idea. But like I said, there may be a better way to do it.

    Code (CSharp):
    1. [System.Serializable]
    2. public class Stat
    3. {
    4.  
    5.     [SerializeField]
    6.     private int baseValue;
    7.  
    8.     [SerializeField]
    9.     private List<int> additiveModifiers = new List<int>();
    10.  
    11.     //Method getters and setters as opposed to properties because Unity can't render properties in Inspector
    12.     public int GetBaseValue()
    13.     {
    14.         return baseValue;
    15.     }
    16.  
    17.     public void SetBaseValue(int value)
    18.     {
    19.         baseValue = value;
    20.     }
    21.  
    22.     public byte[] Serialize()
    23.     {
    24.         byte[] serialized = new byte[8 + (additiveModifiers.Count * 4)];
    25.         int location = 0;
    26.         Array.Copy(BitConverter.GetBytes(baseValue), 0, serialized, location, 4);
    27.         location += 4;
    28.         Array.Copy(BitConverter.GetBytes(additiveModifiers.Count), 0, serialized, location, 4);
    29.         location += 4;
    30.  
    31.         foreach (int mod in additiveModifiers)
    32.         {
    33.             Array.Copy(BitConverter.GetBytes(mod), 0, serialized, location, 4);
    34.             location += 4;
    35.         }
    36.  
    37.         return serialized;
    38.    
    39.     }
    40.  
    41.     public void Deserialize(byte[] serialized)
    42.     {
    43.         int location = 0;
    44.         baseValue = BitConverter.ToInt32(serialized, location);
    45.         location += 4;
    46.         int listLength = BitConverter.ToInt32(serialized, location);
    47.         location += 4;
    48.  
    49.         int looper = 0;
    50.         while (looper < listLength)
    51.         {
    52.             additiveModifiers.Add(BitConverter.ToInt32(serialized, location));
    53.             location += 4;
    54.             looper++;
    55.         }
    56.     }
    57.  
    58. }
    edit: Sorry, forgot you need to add to the top of the script:
    Code (csharp):
    1. using System;
     
    Last edited: Feb 23, 2021
    LukeDawn and ForkyTheEditor like this.