【问题标题】:Serialize Vector3d datatype in photon unity在光子统一中序列化 Vector3d 数据类型
【发布时间】:2021-07-14 16:26:56
【问题描述】:

我想在 PUN RPC 参数中使用 vector3d 数据类型,但 Photon 不接受 vector3d。我们需要注册并序列化它以在 RPC 方法中使用。我的序列化代码有一些问题。

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;
        }
    }
}

【问题讨论】:

  • 我建议您尝试将 vo.x, vo.y, vo.z 转换为 double 以消除注释错误。
  • 好的,我试试这个
  • @JesúsNarváez 如果错误已经表明给定的double 不能转换为short(该方法期望的类型)然后将(已经!)double 值转换为@987654325 @ 不会有太大帮助 ;)
  • 我通过提取 x、y 和 z 坐标将 vector3d 数据类型转换为 vector3 解决了这个问题。感谢您的帮助。

标签: c# unity3d serialization photon


【解决方案1】:

ExitGames.Client.Photon.Protocol.Serialize 实际上只(反)序列化shortintfloat

但是,您可以轻松定义自己的 double (de) 序列化,例如使用BitConverter 和/或Buffer.BlockCopy

请注意,您的数组还是错误的!一个double has not 4 but rather 8 bytes

我建议你使用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;
    }
}

或者一个可能稍微更有效的方法是直接使用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;
    }
}

现在请允许我问一个问题:你真的需要 Vector3ddouble 值吗?

Unity 中的所有内容基本上都使用float,所以在某些时候你无论如何都会失去精度。那么为什么在同步时不丢失精度呢?

并且 afaik Vector3 在 Photon 中具有内置支持,因此无需编写/维护自定义代码。


如果在同步时丢失精度是可以的,但你仍然想使用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);

然后接收只需确保它使用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;
        

但话又说回来,为什么不首先使用Vector3,假设它如前所述直接支持。

【讨论】:

  • 感谢您的帮助。我正在开发一个体素游戏,我希望将 vector3d 的 voxelCenter 数据类型传递到 RPC 的参数中。
猜你喜欢
  • 2018-08-01
  • 2017-05-07
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多