无法反序列化数据
unable to de-serialize data
我开始将 Unity 游戏创建为 Visual Studio 项目。我创建了一个用于测试的副项目(WinForms),因为我不知道单元测试。在那里,我的所有代码都能完美运行,即使使用的 protobuf-net DLL 是用于 Unity 的,序列化 class 也能完美运行。现在,当我开始在 Unity 上工作时,我为 protobuf-net 和 MySQL.Data 复制了我所有的代码和 DLL。出于某种原因,我无法使用(基本上)相同的代码。我在反序列化时总是得到一个异常,主要是这个:
Invalid field in source data: 0
还有这个
Unexpected end-group in source data; this usually means the source data is corrupt
这是最后一个异常的堆栈跟踪:
ProtoBuf.ProtoException: Unexpected end-group in source data; this usually means the source data is corrupt
at ProtoBuf.ProtoReader.ReadFieldHeader ()
at (wrapper dynamic-method) NeohumanSoftware.AoN.UserInformation.User.proto_2 (object,ProtoBuf.ProtoReader)
at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read (object,ProtoBuf.ProtoReader)
at ProtoBuf.Meta.RuntimeTypeModel.Deserialize (int,object,ProtoBuf.ProtoReader)
at ProtoBuf.Meta.TypeModel.DeserializeCore (ProtoBuf.ProtoReader,System.Type,object,bool)
at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type,ProtoBuf.SerializationContext)
at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type)
at ProtoBuf.Serializer.Deserialize (System.IO.Stream) <0x000ae>
at NeohumanSoftware.AoN.Storage.SerializationHandler.DeSerialize (string) <0x00140>
at NeohumanSoftware.AoN.Storage.DataHandler.DeserializeUser (string)
我省略了堆栈跟踪的最后一部分,因为它不相关。我不明白为什么它在 Visual Studio 中有效,但在 Unity 中无效。这是序列化程序:
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, ToSerialize);
return ms.ToArray();
}
这是反序列化器:
using (MemoryStream ms = new MemoryStream(ToDeSerialize))
{
return Serializer.Deserialize<T>(ms);
}
这是要序列化的对象,它是游戏的 "heart",因为一切都来自 User.user:
[ProtoContract]
internal class User
{
internal static User user { get; set; }
[ProtoMember(1)]
internal Something uSomething { get; private set; }
[ProtoMember(2)]
internal bool uSomething2 { get; set; }
[ProtoMember(3)]
internal Something3 uSomething3 { get; set; }
[ProtoMember(4)]
internal Something4 uSomething4 { get; private set; }
[ProtoMember(5)]
internal Something5 uSomething5 { get; private set; }
所有这些自定义 classes 都有 [ProtoContract] 属性以及至少一个 [ProtoMember],除了这两个我不使用任何其他属性。这就是游戏的流程:
- 数据已创建。
- 数据已序列化。
- 传递序列化数据进行加密 (RijndaelManaged)。
- 加密和序列化的数据被写入文件。
- 游戏结束
- 数据从文件加载。
- 使用完全相同的密钥和 IV(随机生成和存储)未加密数据
- 数据被反序列化。
- 游戏开始
编辑:
尝试使用 Visual Studio 的项目反序列化 Unity 的数据 NOT 行不通。尝试使用 Unity 反序列化 Visual Studio 的数据确实 NOT 有效。 Unity好像一点都不喜欢protobuf-net...
编辑2:
我将序列化器方法更改为:
byte[] b;
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, toXML);
b = new byte[ms.Position];
var fullB = ms.GetBuffer();
Array.Copy(fullB, b, b.Length);
}
这就是我得到的:
ProtoBuf.ProtoException: Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see Using Protobuf-net, I suddenly got an exception about an unknown wire-type
at ProtoBuf.ProtoReader.SkipField ()
at (wrapper dynamic-method) NeohumanSoftware.AoN.UserInformation.User.proto_2 (object,ProtoBuf.ProtoReader)
at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read (object,ProtoBuf.ProtoReader)
at ProtoBuf.Meta.RuntimeTypeModel.Deserialize (int,object,ProtoBuf.ProtoReader)
at ProtoBuf.Meta.TypeModel.DeserializeCore (ProtoBuf.ProtoReader,System.Type,object,bool)
at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type,ProtoBuf.SerializationContext)
at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type)
at ProtoBuf.Serializer.Deserialize (System.IO.Stream) <0x000ae>
如果有帮助,这些是读取和写入文件的方法:
internal static void SaveUser(string userSerialized)
{
File.WriteAllText(SomePath, userSerialized);
}
internal static void LoadUser(string userSerialized)
{
File.ReadAllText(SomePath);
}
编辑 3:
在Unity的项目中,我有这些我在Visual Studio的项目中没有的:
internal static Coordinates FromVector3(Vector3 vector)
{
return new Coordinates(vector.x, vector.y, vector.z);
}
internal static Vector3 ToVector3(Coordinates c)
{
return new Vector3(c.X, c.Y, c.Z);
}
这些在坐标 class 中,它有 X、Y 和 Z 的 [ProtoContract] 和 [ProtoMember]。注释掉这 2 个方法可以阻止我接收异常,但序列化仍然不起作用(用户属性都是"new")
已解决
在放弃了对 protobuf-net 的所有希望后,我切换到 DataCotractSerializer,它以某种方式在 Unity 上工作。我仍然遇到很多问题,所以我决定关闭加密并使用 Visual Studio 阅读 XML; 文件完全没问题。我的 3 个事件处理程序仍然存在很多问题(2 个在游戏开始时连接,另一个在每次创建特殊对象时连接),所以我不得不删除事件处理程序并手动执行操作(这很痛苦a$$)。
在所有这一切之后,我设法重新添加了 Protobuf-net,并且一切正常(请注意,protobuf-net 给了我一个 89 字节的文件,而不是 DCS 的 3.5 KB 文件)
所以,这个极其奇怪的问题的最终解决方案是:
- 禁用功能齐全的 RijndaelManaged 实施
- 禁用所有事件处理程序
如果有人能帮助我理解为什么 RijdnaelManaged 在 Visual Studio 而不是 Unity 上工作,请发表评论。
我开始将 Unity 游戏创建为 Visual Studio 项目。我创建了一个用于测试的副项目(WinForms),因为我不知道单元测试。在那里,我的所有代码都能完美运行,即使使用的 protobuf-net DLL 是用于 Unity 的,序列化 class 也能完美运行。现在,当我开始在 Unity 上工作时,我为 protobuf-net 和 MySQL.Data 复制了我所有的代码和 DLL。出于某种原因,我无法使用(基本上)相同的代码。我在反序列化时总是得到一个异常,主要是这个:
Invalid field in source data: 0
还有这个
Unexpected end-group in source data; this usually means the source data is corrupt
这是最后一个异常的堆栈跟踪:
ProtoBuf.ProtoException: Unexpected end-group in source data; this usually means the source data is corrupt at ProtoBuf.ProtoReader.ReadFieldHeader () at (wrapper dynamic-method) NeohumanSoftware.AoN.UserInformation.User.proto_2 (object,ProtoBuf.ProtoReader) at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read (object,ProtoBuf.ProtoReader) at ProtoBuf.Meta.RuntimeTypeModel.Deserialize (int,object,ProtoBuf.ProtoReader) at ProtoBuf.Meta.TypeModel.DeserializeCore (ProtoBuf.ProtoReader,System.Type,object,bool) at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type,ProtoBuf.SerializationContext) at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type) at ProtoBuf.Serializer.Deserialize (System.IO.Stream) <0x000ae> at NeohumanSoftware.AoN.Storage.SerializationHandler.DeSerialize (string) <0x00140> at NeohumanSoftware.AoN.Storage.DataHandler.DeserializeUser (string)
我省略了堆栈跟踪的最后一部分,因为它不相关。我不明白为什么它在 Visual Studio 中有效,但在 Unity 中无效。这是序列化程序:
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, ToSerialize);
return ms.ToArray();
}
这是反序列化器:
using (MemoryStream ms = new MemoryStream(ToDeSerialize))
{
return Serializer.Deserialize<T>(ms);
}
这是要序列化的对象,它是游戏的 "heart",因为一切都来自 User.user:
[ProtoContract]
internal class User
{
internal static User user { get; set; }
[ProtoMember(1)]
internal Something uSomething { get; private set; }
[ProtoMember(2)]
internal bool uSomething2 { get; set; }
[ProtoMember(3)]
internal Something3 uSomething3 { get; set; }
[ProtoMember(4)]
internal Something4 uSomething4 { get; private set; }
[ProtoMember(5)]
internal Something5 uSomething5 { get; private set; }
所有这些自定义 classes 都有 [ProtoContract] 属性以及至少一个 [ProtoMember],除了这两个我不使用任何其他属性。这就是游戏的流程:
- 数据已创建。
- 数据已序列化。
- 传递序列化数据进行加密 (RijndaelManaged)。
- 加密和序列化的数据被写入文件。
- 游戏结束
- 数据从文件加载。
- 使用完全相同的密钥和 IV(随机生成和存储)未加密数据
- 数据被反序列化。
- 游戏开始
编辑: 尝试使用 Visual Studio 的项目反序列化 Unity 的数据 NOT 行不通。尝试使用 Unity 反序列化 Visual Studio 的数据确实 NOT 有效。 Unity好像一点都不喜欢protobuf-net...
编辑2: 我将序列化器方法更改为:
byte[] b;
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, toXML);
b = new byte[ms.Position];
var fullB = ms.GetBuffer();
Array.Copy(fullB, b, b.Length);
}
这就是我得到的:
ProtoBuf.ProtoException: Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see Using Protobuf-net, I suddenly got an exception about an unknown wire-type at ProtoBuf.ProtoReader.SkipField () at (wrapper dynamic-method) NeohumanSoftware.AoN.UserInformation.User.proto_2 (object,ProtoBuf.ProtoReader) at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read (object,ProtoBuf.ProtoReader) at ProtoBuf.Meta.RuntimeTypeModel.Deserialize (int,object,ProtoBuf.ProtoReader) at ProtoBuf.Meta.TypeModel.DeserializeCore (ProtoBuf.ProtoReader,System.Type,object,bool) at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type,ProtoBuf.SerializationContext) at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream,object,System.Type) at ProtoBuf.Serializer.Deserialize (System.IO.Stream) <0x000ae>
如果有帮助,这些是读取和写入文件的方法:
internal static void SaveUser(string userSerialized)
{
File.WriteAllText(SomePath, userSerialized);
}
internal static void LoadUser(string userSerialized)
{
File.ReadAllText(SomePath);
}
编辑 3: 在Unity的项目中,我有这些我在Visual Studio的项目中没有的:
internal static Coordinates FromVector3(Vector3 vector)
{
return new Coordinates(vector.x, vector.y, vector.z);
}
internal static Vector3 ToVector3(Coordinates c)
{
return new Vector3(c.X, c.Y, c.Z);
}
这些在坐标 class 中,它有 X、Y 和 Z 的 [ProtoContract] 和 [ProtoMember]。注释掉这 2 个方法可以阻止我接收异常,但序列化仍然不起作用(用户属性都是"new")
已解决
在放弃了对 protobuf-net 的所有希望后,我切换到 DataCotractSerializer,它以某种方式在 Unity 上工作。我仍然遇到很多问题,所以我决定关闭加密并使用 Visual Studio 阅读 XML; 文件完全没问题。我的 3 个事件处理程序仍然存在很多问题(2 个在游戏开始时连接,另一个在每次创建特殊对象时连接),所以我不得不删除事件处理程序并手动执行操作(这很痛苦a$$)。 在所有这一切之后,我设法重新添加了 Protobuf-net,并且一切正常(请注意,protobuf-net 给了我一个 89 字节的文件,而不是 DCS 的 3.5 KB 文件)
所以,这个极其奇怪的问题的最终解决方案是:
- 禁用功能齐全的 RijndaelManaged 实施
- 禁用所有事件处理程序
如果有人能帮助我理解为什么 RijdnaelManaged 在 Visual Studio 而不是 Unity 上工作,请发表评论。