Search Unity

Resolved How to serialize a BitVector32 with INetworkSerializable

Discussion in 'Netcode for GameObjects' started by Sycab, Nov 24, 2022.

  1. Sycab

    Sycab

    Joined:
    Jul 11, 2020
    Posts:
    10
    Hey guys,

    in order to optimize the size my input message I send to the server I would like to group all button inputs in a BitVector.
    In order to achieve this I have to implement custom serialization as mentioned in the documentation here and here. Unfortunately, I did not have any success with this, and would appreciate some guidance!
    Thanks :)
     
  2. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Hi @Sycab what did you try? Do you have some code to share?
     
  3. Sycab

    Sycab

    Joined:
    Jul 11, 2020
    Posts:
    10
    Honestly, I am quite lost on this. I have not worked with custom serialization or BitVectors before, so I don't really have an idea what I am doing here.

    Code (CSharp):
    1.  
    2. public static class SerializationExtensions
    3. {
    4.         private static int[] _masks = new int[32];
    5.  
    6.         public static void SerializeValue<TReaderWriter>(this    BufferSerializer<TReaderWriter> serializer,
    7.             ref BitVector32 bitVector) where TReaderWriter: IReaderWriter
    8.         {
    9.             if (serializer.IsReader) {
    10.                 bitVector = new BitVector32();
    11.             }
    12.  
    13.             for (int i = 0; i < 32; i++)
    14.             {
    15.                 serializer.SerializeValue(ref bitVector[_masks[i]]);  /* ERROR: Indexer access  returns temporary value. 'ref'
    16.                 argument must be an assignable variable, field, or an array element */
    17.             }
    18.         }
    19.  }
    20.  
    I have tried using the example from the documentation and serializing the values of the bitvector individually, similarly to how an array is serialized This results in the above error though.
     
  4. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    @Sycab Maybe the WeaponBooster example here can help? What I'm suggesting is that you can try creating your own struct that wraps a BitVector32, and then implement the `INetworkSerializable` interface to make it possible to sync it over the network
     
  5. Sycab

    Sycab

    Joined:
    Jul 11, 2020
    Posts:
    10
    Thank you for the suggestion, but I think I wasn't clear on what my problem is.
    So for the input message I already created a struct implementing the interface and that works fine.

    Input Message:
    Code (CSharp):
    1.  
    2. public struct InputMessage : INetworkSerializable
    3. {
    4.     // Limit ~508 bytes for unreliable rpc's
    5.     public uint client_tick_number;
    6.     public float delta_time;
    7.     public PlayerInputs[] player_inputs;
    8.  
    9.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter {
    10.         serializer.SerializeValue(ref client_tick_number);
    11.         serializer.SerializeValue(ref delta_time);
    12.  
    13.         serializer.SerializeValue(ref player_inputs);
    14.      
    15.         // Define Length of array
    16.         int length = 0;
    17.         if (!serializer.IsReader) {
    18.             length = player_inputs.Length;
    19.         }
    20.         serializer.SerializeValue(ref length);
    21.      
    22.         // Read Array
    23.         if (serializer.IsReader) {
    24.             player_inputs = new PlayerInputs[length];
    25.         }
    26.      
    27.         // Serialize Input Array Elements
    28.         for (int n = 0; n < length; n++) {
    29.             serializer.SerializeValue(ref player_inputs[n]);
    30.         }
    31.      
    32.     }
    33. }
    34.  
    Player Input Struct:
    Code (CSharp):
    1.  
    2. public struct PlayerInputs : INetworkSerializable
    3. {
    4.     // 21 bytes currently
    5.     // Joysticks
    6.     public Vector2 left_stick_input;
    7.     public Vector2 right_stick_input;
    8.  
    9.     // Instead of sending each button individually, I would like to group them into this bit vector
    10.     public BitVector32 bitVector32;
    11.  
    12.     // Button enums (1 byte each)
    13.     public KeyState basic_attack_input;
    14.     public KeyState basic_ranged_input;
    15.  
    16.     public KeyState dash_input;
    17.     public KeyState cast_01_input;
    18.     public KeyState cast_02_input;
    19.  
    20.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter {
    21.  
    22.         if (serializer.IsReader)
    23.         {
    24.             var reader = serializer.GetFastBufferReader();
    25.             reader.ReadValueSafe(out bitVector32); /* Error: The constraints for type arguments are not satisfied. */
    26.         }
    27.         else
    28.         {
    29.             var writer = serializer.GetFastBufferWriter();
    30.             writer.WriteValueSafe(bitVector32); /* Error: The constraints for type arguments are not satisfied.*/
    31.         }
    32.      
    33.         serializer.SerializeValue(ref left_stick_input);
    34.         serializer.SerializeValue(ref right_stick_input);
    35.      
    36.         serializer.SerializeValue(ref basic_attack_input);
    37.         serializer.SerializeValue(ref basic_ranged_input);
    38.      
    39.         serializer.SerializeValue(ref dash_input);
    40.         serializer.SerializeValue(ref cast_01_input);
    41.         serializer.SerializeValue(ref cast_02_input);
    42.     }
    43. }
    44.  
    The problem here is that I cannot just pass the BitVector32 to the Serializer since it only handles built-in types etc. From what I understood from the documentation that I have linked above, I could override the serialization for all types. That is the part that I am not able to figure out though, and that's what I tried here.

     
  6. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    666
    Try this:
    Code (CSharp):
    1.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    2.     {
    3.         if(serializer.IsWriter)
    4.         {
    5.             serializer.GetFastBufferWriter().WriteValueSafe(bitVector.Data);
    6.         }
    7.  
    8.         if(serializer.IsReader)
    9.         {
    10.             serializer.GetFastBufferReader().ReadValueSafe<int>(out int bitVectorData);
    11.  
    12.             bitVector = new BitVector32(bitVectorData);
    13.  
    14.             Debug.Log("BitVector " + bitVector);
    15.         }
    16.     }
     
    RikuTheFuffs-U and Sycab like this.
  7. Sycab

    Sycab

    Joined:
    Jul 11, 2020
    Posts:
    10
    This works! Thank's a lot and also thank's to @RikuTheFuffs-U for the replies :)
     
    RikuTheFuffs-U and cerestorm like this.