Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved I am unable to customize the serialization structure

Discussion in 'Netcode for GameObjects' started by Yuze_75, May 1, 2024.

  1. Yuze_75

    Yuze_75

    Joined:
    Mar 14, 2022
    Posts:
    18
    My Unity version is 2023.2.17, and the Netcode version is 1.8.1

    I refer to this article https://docs-multiplayer.unity3d.com/netcode/1.8.1/advanced-topics/custom-serialization/ To perform custom serialization extensions, I need to serialize some Structs from external libraries. However, even if I follow the corresponding definitions in the documentation, there will still be issues during compilation I tried to define any custom Struct but failed, but when I adjusted the data structure to Class, it could be successfully serialized. What is the reason for this?

    Code (CSharp):
    1. #nullable enable
    2. using Unity.Netcode;
    3.  
    4. public static class SerializationExtensions
    5. {
    6.     public static void ReadValueSafe(this FastBufferReader reader, out MyStruct value)
    7.     {
    8.         ByteUnpacker.ReadValuePacked(reader, out int i);
    9.         value = new MyStruct { Value = i };
    10.     }
    11.  
    12.     public static void WriterValueSafe(this FastBufferWriter writer, in MyStruct value)
    13.     {
    14.         BytePacker.WriteValuePacked(writer, value.Value);
    15.     }
    16.    
    17.     public static void ReadValueSafe(this FastBufferReader reader, out MyClass value)
    18.     {
    19.         ByteUnpacker.ReadValuePacked(reader, out int i);
    20.         value = new MyClass { Value = i };
    21.     }
    22.  
    23.     public static void WriteValueSafe(this FastBufferWriter writer, in MyClass value)
    24.     {
    25.         BytePacker.WriteValuePacked(writer, value.Value);
    26.     }
    27. }
    28.  
    29. public struct MyStruct
    30. {
    31.     public int Value;
    32. }
    33.  
    34. public class MyClass
    35. {
    36.     public int Value;
    37. }
    Code (CSharp):
    1. #nullable enable
    2. using Unity.Netcode;
    3. using UnityEngine;
    4.  
    5. public partial class Test : NetworkBehaviour
    6. {
    7.  
    8.     [Rpc(SendTo.Everyone)]
    9.     private void TestRpc(MyClass value) // It works
    10.     {
    11.         Debug.Log($"value: {value}");
    12.     }
    13.  
    14.     [Rpc(SendTo.Everyone)]
    15.     private void TestRpc(MyStruct value) // It not works
    16.     {
    17.         Debug.Log($"value: {value}");
    18.     }
    19. }
    upload_2024-5-1_11-36-53.png
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,479
    RTFM ;)

    MyStruct does not implement the INetworkSerializable interface.

    Classes cannot be serialized, this probably just fails silently for the same reason: it doesn't implement INetworkSerializable. So there's probably no "is this a value type" check running.
     
  3. Yuze_75

    Yuze_75

    Joined:
    Mar 14, 2022
    Posts:
    18
    I am well aware that serialization of a Structure can be achieved by inheriting INetworkSerializable or INetworkSerializeByMemcpy, but my current problem is that I need to serialize a structure from another library I am using, which I cannot change its inherited interface type. I can only try to serialize it in some ways


    The first method is to use a Wrapper Struct to wrap the data in this Struct, transfer it, and then restore it Although this can achieve the desired effect, it requires additional processing when sending and receiving Rpcs. I don't like this method


    The second one is the method I saw in the Netcode article, which allows Netcode to collect this serialization method by defining extension methods. The defined objects can be serialized and deserialized during Rpc sending without inheriting INetworkSerializable, and it explains that custom serialization has a higher priority than INetworkSerializable


    My problem now is that I can only serialize the class using this method. If I serialize the struct, it will report an error and cannot collect the corresponding extension method

    I am well aware that serialization of a Structure can be achieved by inheriting INetworkSerializable or INetworkSerializeByMemcpy, but my current problem is that I need to serialize a structure from another library I am using, which I cannot change its inherited interface type. I can only try to serialize it in some ways


    The first method is to use a Wrapper Struct to wrap the data in this Struct, transfer it, and then restore it Although this can achieve the desired effect, it requires additional processing when sending and receiving Rpcs. I don't like this method


    The second one is the method I saw in the Netcode article, which allows Netcode to collect this serialization method by defining extension methods. The defined objects can be serialized and deserialized during Rpc sending without inheriting INetworkSerializable, and it explains that custom serialization has a higher priority than INetworkSerializable


    My problem now is that I can only serialize the class using this method. If I serialize the struct, it will report an error and cannot collect the corresponding extension method

    upload_2024-5-1_15-58-6.png

    upload_2024-5-1_15-58-15.png
     
  4. Yuze_75

    Yuze_75

    Joined:
    Mar 14, 2022
    Posts:
    18
    Then I also tested the serialization method of MyClass, an extension method, and it worked properly without any issues.
    I just want to know why the same extension method doesn't work on Struct
     
  5. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,479
    I'm sorry, I didn't get the full scope of the situation.

    I believe the clue is in this statement:
    Try adding a managed type such as an object to MyStruct to see if that works. If so, that would indicate the system is intended to be used only for types that are or contain at least one managed type.
     
  6. Yuze_75

    Yuze_75

    Joined:
    Mar 14, 2022
    Posts:
    18
    I have adjusted the code to this, but it still cannot be compiled. It is still the same issue as before, and it cannot find the serialization method for MyStruct

    Code (CSharp):
    1. #nullable enable
    2. using Unity.Netcode;
    3.  
    4. public static class SerializationExtensions
    5. {
    6.     public static void ReadValueSafe(this FastBufferReader reader, out MyStruct value)
    7.     {
    8.         reader.ReadValueSafe(out int i);
    9.         reader.ReadValueSafe(out int j);
    10.         value = new MyStruct { Value = i, MyClass = new MyClass { Value = j } };
    11.     }
    12.  
    13.     public static void WriterValueSafe(this FastBufferWriter writer, in MyStruct value)
    14.     {
    15.         writer.WriteValueSafe(value.Value);
    16.         writer.WriteValueSafe(value.MyClass?.Value ?? 0);
    17.     }
    18.  
    19.     public static void ReadValueSafe(this FastBufferReader reader, out MyClass value)
    20.     {
    21.         reader.ReadValueSafe(out int i);
    22.         value = new MyClass { Value = i };
    23.     }
    24.  
    25.     public static void WriteValueSafe(this FastBufferWriter writer, in MyClass value)
    26.     {
    27.         writer.WriteValueSafe(value.Value);
    28.     }
    29. }
    30.  
    31. public struct MyStruct
    32. {
    33.     public int Value;
    34.     public MyClass? MyClass;
    35. }
    36.  
    37. public class MyClass
    38. {
    39.     public int Value;
    40. }
    upload_2024-5-1_16-38-16.png
     
  7. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,479
    This may be a limitation of the system because it may assume you only need to use it on managed types, whereas unmanaged types can simply use INetworkSerializable (except as in your case).

    But if you add MyStruct to MyClass you have achieved your goal. ;)

    You could also inspect the code that's calling these ReadValueSafe methods to see if they have a separate code path for unmanaged types.
     
  8. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    674
    I can't see why this isn't working. As a possible alternative you could try ForceNetworkSerializeByMemcpy if the struct implements IEquatable.
     
    Yuze_75 likes this.