com.unity.netcode.gameobjects icon indicating copy to clipboard operation
com.unity.netcode.gameobjects copied to clipboard

Add built-in serialization for `UnityEngine.Pose`

Open PitouGames opened this issue 2 years ago • 4 comments

Is your feature request related to a problem? Please describe.

Unity provide a primitive struct called Pose, which is a composition of a Vector3 and a Quaternion. This type is not very known, but very usefull, for instance in a single list of waypoints that also need to store their rotation.

This type is not listed in the documentation: https://docs-multiplayer.unity3d.com/netcode/current/advanced-topics/serialization/unity-primitives/, and doesn't work if used in an Rpc or NetworkVariable.

[ServerRpc()]
private void TestServerRpc(Pose p)
{
    Debug.Log(p);
}
Assets\Scripts\Test.cs(32,13): error  - TestServerRpc - Don't know how to deserialize UnityEngine.Pose. RPC parameter types must either implement INetworkSerializeByMemcpy or INetworkSerializable. If this type is external and you are sure its memory layout makes it serializable by memcpy, you can replace UnityEngine.Pose with ForceNetworkSerializeByMemcpy`1<UnityEngine.Pose>, or you can create extension methods for FastBufferReader.ReadValueSafe(this FastBufferReader, out UnityEngine.Pose) and FastBufferWriter.WriteValueSafe(this FastBufferWriter, in UnityEngine.Pose) to define serialization for this type.
private NetworkList<Pose> poseList = new NetworkList<Pose>();

private void AddAnItem() {
    poseList.Add(new Pose(transform.position, transform.rotation));
}
ArgumentException: Type UnityEngine.Pose is not supported by NetworkVariable`1. If this is a type you can change, then either implement INetworkSerializable or mark it as serializable by memcpy by adding INetworkSerializeByMemcpy to its interface list. If not, assign serialization code to UserNetworkVariableSerialization.WriteValue, UserNetworkVariableSerialization.ReadValue, and UserNetworkVariableSerialization.DuplicateValue, or if it's serializable by memcpy (contains no pointers), wrap it in ForceNetworkSerializeByMemcpy`1.

Describe the solution you'd like Add a default serializer for UnityEngine.Pose.

Describe alternatives you've considered Today, users have to implement their own serializer or send Vector3 and Quaterion separately.

PitouGames avatar Aug 24 '23 17:08 PitouGames

@michalChrobot Hi, I have updated my PR. Please see #2677

PitouGames avatar Apr 19 '25 09:04 PitouGames

Hi, thanks for pinging. We will try to find some time to check it out next week

michalChrobot avatar Apr 19 '25 15:04 michalChrobot

Hi @PitouGames ,

We will look into the possibility of making this a default type. However, you can always create your own Custom Serializers for various types that will work for RPCs, INetworkSerializable, and NetworkVariables.

As an example, adding Pose would look something like this:

/// <summary>
/// Custom Serialization Types
/// Includes <see cref="Pose"/> example.
/// </summary>
public static class SerializationExtensions
{
    public static void InitializePoseNetworkVariable()
    {
        UserNetworkVariableSerialization<Pose>.WriteValue = SerializationExtensions.WriteValueSafe;
        UserNetworkVariableSerialization<Pose>.ReadValue = SerializationExtensions.ReadValueSafe;
    }

    public static void ReadValueSafe(this FastBufferReader reader, out Pose pose)
    {
        reader.ReadValueSafe(out Vector3 position);
        reader.ReadValueSafe(out Quaternion rotation);
        pose = new Pose(position, rotation);
    }

    public static void WriteValueSafe(this FastBufferWriter writer, in Pose pose)
    {
        writer.WriteValueSafe(pose.position);
        writer.WriteValueSafe(pose.rotation);
    }

    public static void SerializeValue<TReaderWriter>(this BufferSerializer<TReaderWriter> serializer, ref Pose pose) where TReaderWriter : IReaderWriter
    {
        if (serializer.IsReader)
        {
            pose = new Pose();
        }
        serializer.SerializeValue(ref pose);
    }
}

You would just need to invoke SerializationExtensions.InitializePoseNetworkVariable when your application starts (i.e. before any NetworkVariable is serialized) in order to add the NetworkVariable support.

NoelStephensUnity avatar Apr 19 '25 18:04 NoelStephensUnity

Thank you to both of you for the reply.

Yes Noel, that is what I meant when I wrote:

Describe alternatives you've considered Today, users have to implement their own serializer or send Vector3 and Quaterion separately.

Thank you for the "official" sample code.

But it's developer work that can be avoided since Pose is an Engine type, just as Vector3 or Quaternion 😉

PitouGames avatar Apr 19 '25 19:04 PitouGames