Protobuf-net在Unity中的序列化与反序列化

Protobuf-net在Unity中的序列化与反序列化

本篇中我们只讲解如何在Unity中对Protobuf-net进行序列化(Serialize)与反序列化(Deserialize),关于Unity的socket网络通信部分我们后续开篇。

首先去Protobuf-net的Google下载点下载protobuf-net类库:https://code.google.com/p/protobuf-net/downloads/list
这里用的是目前最新的protobuf-net r668
下载完毕后打开压缩包,在Full\unity中找到protobuf-net.dll将其添加到项目中。
接下来过程其实类似于我之前的一文章《Protobuf在Java中的简单实例》

①创建proto文件,定义协议格式
首先我们需要创建一个.proto文件来进行测试:

1
2
3
4
5
package com. beitown. net. msg ; //包名
message TestMsg  {
    required  int64 Id = 1 ; 
    required string Name = 2 ;
}

每个字段后标记的“=1”、“=2”这里就不解释了,之前的一篇Protobuf文章中已经做过概述。

②编译Proto文件生成.cs文件
这里我们需要用到一个编译工具ProtoGen,在之前下载的protobuf-net r668.zip中就有。
为了方便管理.proto和.cs文件以及编译快捷,我们可以写一个bat脚本来实现自动编译.proto文件,脚本如下:

1
2
3
@echo off
for  /"delims="  %%i in  ( 'dir /b proto "proto/*.proto"' )  do protogen  -i :proto /%%-o :cs /%%~ni. cs
pause


为了配合这个脚本,需要在ProtoGen文件夹中另外再创建两个子文件夹,一个proto文件夹,一个cs文件夹。批处理会自动寻找proto文件夹下的.proto文件并编译成相应.cs文件保存到cs目录中。
ok,接下来将之前写好的Test.proto文件放到proto文件夹中,执行creat.bat脚本。此时会在cs文件夹下生成一个名为Test.cs的文件。
我们先来观察一下这个Test.cs文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

// Generated from: proto/Test.proto
namespace com . beitown . net . msg
{
   [global :: System . Serializable, global :: ProtoBuf . ProtoContract (Name = @"TestMsg" ) ]
   public  partial  class TestMsg  : global :: ProtoBuf . IExtensible
   {
     public TestMsg ( )  { }
    
     private  long _Id ;
     [global :: ProtoBuf . ProtoMember ( 1, IsRequired  =  true, Name = @"Id", DataFormat  = global :: ProtoBuf . DataFormat . TwosComplement ) ]
     public  long Id
     {
      get  {  return _Id ;  }
      set  { _Id  = value ;  }
     }
     private  string _Name ;
     [global :: ProtoBuf . ProtoMember ( 2, IsRequired  =  true, Name = @"Name", DataFormat  = global :: ProtoBuf . DataFormat . Default ) ]
     public  string Name
     {
      get  {  return _Name ;  }
      set  { _Name  = value ;  }
     }
     private global :: ProtoBuf . IExtension extensionObject ;
    global :: ProtoBuf . IExtension global :: ProtoBuf . IExtensible . GetExtensionObject ( bool createIfMissing )
       {  return global :: ProtoBuf . Extensible . GetExtensionObject ( ref extensionObject, createIfMissing ) ;  }
   }
  
}

和Protobuf-Csharp的编译机制编译出的cs文件比起来要清晰简单很多,同理和java端的编译后文件比起来也非常清晰,这也是Protobuf-net的一个让人觉得亲切的地方,尽管自动生成的代码我们都不会再去手动修改甚至去浏览。
接下来将这个Test.cs文件添加到项目中,即可对TestMsg这个protobuf结构进行操作了。

③序列化与反序列化
在发送数据前我们需要将Protobuf结构进行序列化,在本例中即给之前定义的TestMsg结构体赋值,并将其转换成二进制形式方便通信机制发送。
这里直接写成了静态方法。

i 序列化:

1
2
3
4
5
6
7
8
9
10
11
using  ProtoBuf ;
public  static  byte [ ] Serialize (IExtensible msg )
         {
             byte [ ] result ;
             using  (var stream  =  new MemoryStream ( ) )
             {
                Serializer . Serialize (stream, msg ) ;
                result  = stream . ToArray ( ) ;
             }
             return result ;
         }

IExtensible是ProtoBuf包下的一个公共接口,参考Test.cs的文件结构(TestMsg : global::ProtoBuf.IExtensible)可以发现,在整个规则中所有的的protobuf结构都实现了ProtoBuf.IExtensible这个接口,因此也方面我们的封装。

接下来是反序列化的封装。
ii 反序列化:

1
2
3
4
5
6
7
8
9
10
using  ProtoBuf ;
public  static IExtensible Deserialize <IExtensible > ( byte [ ] message )
         {
            IExtensible result ;
             using  (var stream  =  new MemoryStream (message ) )
             {
                result  = Serializer . Deserialize <IExtensible > (stream ) ;
             }
             return result ;
         }

封装完毕之后我们来看看使用的方法,直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public  class Main  : MonoBehaviour
{
     // Use this for initialization
     void Start ( )
     {
         //建立socket连接之类种种忽略...

        Testmsg protoOut =  new Testmsg  ( ) ;
        protoOut . Id  =  10046 ;
        protoOut . name =  "beitown" ;
         byte [ ] bytes  = Serialize (protoOut ) ;

         //socket.send(bytes)之类种种,发送到字节流中...

     }

     // Update is called once per frame
     void Update ( )
     {
         //当获取到一个消息在bytes中
        TestMsg protoIn  =  (TestMsg )Deserialize <TestMsg > (bytes ) ; //强转成TestMsg类型
        Debug . log ( "Id: "  + protoIn . Id ) ; //获取Id
        Debug . log ( "Name: "  + protoIn . Name ) ; //获取Name

     }
}

以上代码写的略做精简,不涉及任何通信部分的描述,大家需要根据自己的情况来进行另外的封装,这里就不再描述了,后续可能会写一篇UnitySocket封装和智能Command的文章,到时再做叙述。
参照本文中的内容再加上一个简单的Socket通信,即可完成一个简单的Unity Protobuf-net的小Demo,感兴趣的朋友可以继续,望能抛砖引玉。
本篇到此,谢谢关注。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值