简体   繁体   English

在光子统一中序列化 Vector3d 数据类型

[英]Serialize Vector3d datatype in photon unity

I want to use vector3d datatype in PUN RPC parameter but Photon doesn't accept vector3d.我想在 PUN RPC 参数中使用 vector3d 数据类型,但 Photon 不接受 vector3d。 We need to register and serialize it to use in RPC method.我们需要注册并序列化它以在 RPC 方法中使用。 I am having some issues with the serialization code.我对序列化代码有一些问题。

namespace VoxelPlay
{
    internal static class MyCustomDataType
    {
        
        internal static void Register()
        {

            PhotonPeer.RegisterType(typeof(Vector3d), (byte)'V', SerializeVector3d, DeserializeVector3d);

        }

        public static readonly byte[] memVector3d = new byte[3 * 4];

        private static short SerializeVector3d(StreamBuffer outStream, object customobject)
        {
            Vector3d vo = (Vector3d)customobject;

            int index = 0;
            lock (memVector3d)
            {
                byte[] bytes = memVector3d;
                Protocol.Serialize(vo.x, bytes, ref index);      //Getting error: Cannot convert from double to short
                Protocol.Serialize(vo.y, bytes, ref index);
                Protocol.Serialize(vo.z, bytes, ref index);
                outStream.Write(bytes, 0, 3 * 4);
            }
            return 3 * 4;
        }

        private static object DeserializeVector3d(StreamBuffer inStream, short length)
        {
            Vector3d vo = new Vector3d();
            lock (memVector3d)
            {
                inStream.Read(memVector3d, 0, 3 * 4);
                int index = 0;
                Protocol.Deserialize(out vo.x, memVector3d, ref index);
                Protocol.Deserialize(out vo.y, memVector3d, ref index);
                Protocol.Deserialize(out vo.z, memVector3d, ref index);
            }

            return vo;
        }
    }
}

ExitGames.Client.Photon.Protocol.Serialize indeed only (de)serializes short , int or float . ExitGames.Client.Photon.Protocol.Serialize实际上只(反)序列化shortintfloat

However, you could easily define your very own double (de) serialization eg usingBitConverter and/or Buffer.BlockCopy但是,您可以轻松定义自己的double (反)序列化,例如使用BitConverter和/或Buffer.BlockCopy

Note that your array was wrong anyway!请注意,您的数组无论如何都是错误的! A double has not 4 but rather 8 bytes double数不是4 ,而是8个字节

I would recommend you use sizeof for this kind of things;)我会建议你使用sizeof做这种事情;)

internal static class MyCustomDataType
{
    internal static void Register()
    {
        PhotonPeer.RegisterType(typeof(Vector3d), (byte)'V', SerializeVector3d, DeserializeVector3d);
    }

    // Note: Your array had the wrong length anyway!
    // double is not 4 but 8 bytes!
    // Instead of magic numbers rather use sizeof in general
    public const short ByteSize = 3 * sizeof(double);
    public static readonly byte[] memVector3d = new byte[ByteSize];

    private static short SerializeVector3d(StreamBuffer outStream, object customobject)
    {
        var vo = (Vector3d)customobject;

        var index = 0;
        lock (memVector3d)
        {
            ToBytes(vo.x, memVector3d, ref index);      
            ToBytes(vo.y, memVector3d, ref index);
            ToBytes(vo.z, memVector3d, ref index);
            outStream.Write(memVector3d, 0, ByteSize);
        }
        return ByteSize;
    }

    private static object DeserializeVector3d(StreamBuffer inStream, short length)
    {
        var vo = new Vector3d();
        lock (memVector3d)
        {
            inStream.Read(memVector3d, 0, ByteSize);
            int index = 0;
            ReadDouble(out vo.x, memVector3d, ref index);
            ReadDouble(out vo.y, memVector3d, ref index);
            ReadDouble(out vo.z, memVector3d, ref index);
        }

        return vo;
    }

    private static void byte[] ToBytes(double input, byte[] bytes, ref offset)
    {
        // Converts the double to a byte[] of length "sizeof(double)" (=8)
        var doubleBytes = BitConverter.ToBytes(input);
        // Copy the content of the doubleSize into the combined bytes
        // starting at current offset
        Buffer.BlockCopy(doubleBytes, 0, bytes, offset, doubleBytes.Length);
        // increase by the copied size
        offset += doubleBytes.Length;
    }

    private static void ReadDouble(out double value, byte[] bytes, ref offset)
    {
        // Reads "sizeof(double)" (=8) byes starting at given offset
        // and converts them to a double
        value = BitConverter.ToDouble(bytes, offset);
        // Increase by the amount of read bytes
        offset+=sizeof(double);
        return output;
    }
}

Or a probably slightly more efficient approach would be to use the Buffer.BlockCopy directly for converting the values like或者一种可能稍微更有效的方法是直接使用Buffer.BlockCopy来转换像这样的值

internal static class MyCustomDataType
{
    internal static void Register()
    {
        PhotonPeer.RegisterType(typeof(Vector3d), (byte)'V', SerializeVector3d, DeserializeVector3d);
    }

    // Note: Your array had the wrong length anyway!
    // double is not 4 but 8 bytes!
    // Instead of magic numbers rather use sizeof in general
    public const short ByteSize = 3 * sizeof(double);
    public static readonly byte[] memVector3d = new byte[ByteSize];
    public static readonly double[] doubles = new double[3];

    private static short SerializeVector3d(StreamBuffer outStream, object customobject)
    {
        var vo = (Vector3d)customobject;

        lock (memVector3d)
        {
            // Fill the doubles array
            doubles[0] = vo.x;
            doubles[1] = vo.y;
            doubles[2] = vo.z;

            // directly copy that array on the bytes level
            Buffer.BlockCopy(floats, 0, memVector3d, 0, ByteSize);
            
            outStream.Write(memVector3d, 0, ByteSize);
        }
        return ByteSize;
    }

    private static object DeserializeVector3d(StreamBuffer inStream, short length)
    {
        var vo = new Vector3d();
        lock (memVector3d)
        {
            inStream.Read(memVector3d, 0, ByteSize);

            // Just the other way round directly copy into the doubles array on byte level
            Buffer.BlockCopy(memVector3d, 0, floats, 0, ByteSize);
            
            vo.x = doubles[0];
            vo.y = doubles[1];
            vo.z = doubles[2];
        }

        return vo;
    }
}

And now allow me the question: Do you really need Vector3d with double values?现在请允许我提出一个问题:您真的需要具有double值的Vector3d吗?

Basically everything in Unity uses float anyway so at some point you will lose precision anyway.基本上,Unity 中的所有内容都使用float ,所以在某些时候你无论如何都会失去精度。 So why not already lose the precision while synchronizing?那么为什么在同步时不失去精度呢?

And afaik the Vector3 has built-in support in Photon so no custom code has to be written/maintained.而且, Vector3在 Photon 中具有内置支持,因此无需编写/维护自定义代码。


As alternative if losing precision is ok while synchronizing but you still want to use Vector3d you could probably simply use作为替代方案,如果在同步时丢失精度是可以的,但您仍想使用Vector3d ,您可能只需使用

Protocol.Serialize((float)vo.x, bytes, ref index);
Protocol.Serialize((float)vo.y, bytes, ref index);
Protocol.Serialize((float)vo.z, bytes, ref index);

And then for receiving just make sure it uses the float version然后接收只需确保它使用float版本

Protocol.Deserialize(out float x, memVector3d, ref index);
Protocol.Deserialize(out float y, memVector3d, ref index);
Protocol.Deserialize(out float z, memVector3d, ref index);

vo.x = x;
vo.y = y;
vo.z = z;
        

But then again, why not simply use Vector3 in the first place, assuming it is supported directly as mentioned before.但是话又说回来,为什么不首先简单地使用Vector3 ,假设它如前所述直接支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM