在光子统一中序列化 Vector3d 数据类型
Posted
技术标签:
【中文标题】在光子统一中序列化 Vector3d 数据类型【英文标题】:Serialize Vector3d datatype in photon unity 【发布时间】: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 解决了这个问题。感谢您的帮助。
【参考方案1】:
ExitGames.Client.Photon.Protocol.Serialize
实际上只(反)序列化short
、int
或float
。
但是,您可以轻松定义自己的 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;
现在请允许我问一个问题:你真的需要 Vector3d
和 double
值吗?
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 的参数中。以上是关于在光子统一中序列化 Vector3d 数据类型的主要内容,如果未能解决你的问题,请参考以下文章