Unity 5.x中使用Protobuf

司空海荣
2023-12-01

哎,各种坑,总算整差不多明白了,放了一个github工程,把配套的protobuf-net源码,dll和生成工具都放一起了。

 

注意仔细读README,如果使用mono的,直接把dll放到工程的Plugins目录下就行了,要选择.net 2.0,不能用.net 2.0 subset。

 

如果要使用il2cpp的,需要把协议文件与protobuf-net for Unity的dll文件一起编译成一个dll库,然后用precompile工具生成一个预编译的Serializer,在Unity工程中使用这个Serializer和生成的协议文件库。这样做是因为il2cpp只支持AOT代码,也就是全编译的机器码,但是protobuf-net里面有一些模板库,会在运行时动态生成一些代码来执行,在il2cpp的时候会报错。

下面还是保留了一下以前写的内容,但是后来发现是不对的。即使不使用enum,在有repeated字段的时候,还是会触发JIT的代码导致运行失败。尝试了预先写好一些AOT Function的方法也是不行。后来就直接放弃了,还是用precomplier的方式了。虽然复杂一点,但是写好自动化脚本也还可以。

 

======================= 以前的内容 =====================

还要注意的是,如果要用il2cpp,那么proto文件里面不要引用其他文件中的enum,因为这样会引发protobuf执行一段平台上不支持的JIT代码,使用字符串反射到执行的方法的一块代码。例如,如下的两个proto:

common.proto里面定义了一个enum

enum COMMON_OP
{
    OP_DEFAULT = 0;
    OP_OP1 = 1;
    OP_OP2 = 2;
}

然后在另外一个proto里面的一个消息里使用COMMON_OP时,按照proto2的语法,需要制定默认值:

message somemsg
{
    optional common.COMMON_OP  operation = 1[default = OP_DEFAULT];
}

这样的消息在序列化的时候就会出错,报错信息像这样:

ExecutionEngineException: Attempting to call method 'ProtoBuf.Property.PropertyUtil`1 for 
which no ahead of time (AOT) code was generated. at System.Reflection.MonoMethod.Invoke 
(System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, 
System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in 
<filename unknown>:0

 

把enum换成简单类型int32,用的时候只使用enum的整数值作比较就能规避这个问题。

message somemsg
{
    optional int32  operation = 1;
}

如果有人知道protobuf-net的代码能怎样改改支持这种消息,请留言告诉我。

 

 

 类似资料: