Unity 从 protobuf 2.5 升级到 3.x 【踩坑】

之前使用 protobuf 2.5 的版本来定制和读取表格,为了适应后端 golang 的工具选型,需要将前端的的一些库和工具都升到 3.x 的版本,例如, C# 中要使用 protobuf 需要引入一个编译好的 protobuf-net.dll 库文件。

Protobuf 3.4.x :

1.资源下载:

  • protobuf 源码:

    这里直接选择最新的 Protocol Buffers v3.4.0 ,然后下载源码 Source code (zip) ,至于详细关于 protobuf 3.x 版本的特点可以查看 项目中使用protobuf 3.0

  • gmockgtest 工具:

    E:\Protobuf\3.4.0\tools>git clone -b "3.4.x" https://github.com/google/protobuf.git
    E:\Protobuf\3.4.0\tools>cd protobuf
    E:\Protobuf\3.4.0\tools\protobuf>git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock
    E:\Protobuf\3.4.0\tools\protobuf>cd gmock
    E:\Protobuf\3.4.0\tools\protobuf\gmock>git clone -b release-1.7.0 https://github.com/google/googletest.git gtest

以上两步可以直接通过编写一个自动化脚本来完成,使用不同版本只需修改版本号即可:

::参考文章 https://github.com/google/protobuf/blob/master/cmake/README.md
::默认当前操作系统已安装 git 和 cmake,并配置好了环境变量
echo off & color 0A

::设置所需要的Protobuf版本,最新版本可以在github上查到 https://github.com/google/protobuf
set PROTOBUF_VESION="3.4.x"
echo %PROTOBUF_VESION%
set PROTOBUF_PATH="protobuf_%PROTOBUF_VESION%"
echo %PROTOBUF_PATH%

::从githug上拉取protobuf源代码
git clone -b %PROTOBUF_VESION% https://github.com/google/protobuf.git %PROTOBUF_PATH%

::从github上拉取gmock
cd %PROTOBUF_PATH%
git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock

::从github上拉取gtest
cd gmock
git clone -b release-1.7.0 https://github.com/google/googletest.git gtest

pause

2.源码编译:

旧版本(protobuf 2.5)里面有一个 vsprojects 的目录,直接使用 VS 编辑器打开即可编译,新版本(protobuf 3.x)没有此目录,且改用 CMake 工具来编译源码,使用 CMake 工具来生成 VS 工程,(注:要顺利执行编译需要给 VS 安装 C++ 插件,否则 cmake 编译时会提示找不到 C compiler 和 C++ Compiler:The C compiler identification is unknown,The CXX compiler identification is unknown)具体步骤如下:

  • 安装 CMake ,并将其安装目录下 bin 文件的路径添加到系统环境配置信息中的 Path 中(方便命令行中全局调用此工具);

  • 在上面下载好的 protobuf_3.4.x 文件夹同级目录下新建一个 install 目录用于存储编译完成后 include 和 lib 等文件;

  • 打开 cmake-gui ,设置两个目录地址:where is the source code:E:\Protobuf\3.4.0\tools\protobuf_3.4.x 中的 cmake 目录;where to build the binaries: 自己创建的地址 E:\Protobuf\3.4.0\tools\install,用于存储编译结果的库资源;

  • 点击 Configure 配置要创建的 VS 工程适用的版本,这里我选择的是 "Visual Studio 14 2015 Win64" ,然后点击 Finish 开始进行配置,配置完成会输出 "Configuring done"

  • 点击 Generate 生成对应的 VS 工程,完成则输出 "Generating done"

  • 点击 Open Project 即会在 VS 中打开工程,在编译环境设置中选择 Releasex64 ,然后在 解决方案资源管理器 窗口中选中跟目录,右键 - 生成解决方案

    编译成功会有如下输出:

    ...
    13>------ 已启动生成: 项目: ALL_BUILD, 配置: Release x64 ------
    14>------ 已跳过生成: 项目: check, 配置: Release x64 ------
    14>没有为此解决方案配置选中要生成的项目 
    13>  Building Custom Rule E:/Protobuf/3.4.0/tools/protobuf_3.4.x/cmake/CMakeLists.txt
    13>  CMake does not need to re-run because E:/Protobuf/3.4.0/tools/install/CMakeFiles/generate.stamp is up-to-date.
    15>------ 已跳过生成: 项目: INSTALL, 配置: Release x64 ------
    15>没有为此解决方案配置选中要生成的项目 
    ========== 生成: 成功 13 个,失败 0 个,最新 0 个,跳过 2 个 ==========

    在之前自己创建的 install 目录下会生成一个 Release 目录,从中可以获取 protoc.exe 解释器。

参考 protobuf 官方 API ,将 .proto 转为 .cs 只需一个指令:

protoc --csharp_out=(.cs输出目录) --proto_path=(.proto目录) (.proto名称)

Protobuf-net :

上面步骤完成之后,我们只是得到了目标文件之一的 protoc.exe ,假如要在 Unity 的 C# 层使用的话,还需要用到 protobuf-net 工具中的 protogen.exeprotobuf-net.dll 这些工具,因为 protoc.exe 转化得到的 .cs 脚本 Unity 无法实现解析,只能解析 protobuf-net 转化得到的 .cs 脚本。

下载源码 protobuf-net ,这里需要安装 Visual Studio 2017 才能打开工程文件,当然也可以直接使用 VS 中的 NuGet 工具来下载工程,操作步骤如下:

  • 工具 —> NuGet 包管理器 —> 程序包管理器控制台 打开指令控制台;

  • 然后在 NuGet 官网 搜索制定版本的程序安装包的下载指令,在控制台中输入,这里输入:

    Install-Package protobuf-net -Version 2.3.2

  • 这里我还是直接使用 VS 2017 打开 protobuf-net.sln ,选择 Release 然后生成解决方案,输出如下则表示编译成功:

    ...
    ========== 生成: 成功 6 个,失败 0 个,最新 0 个,跳过 0 个 ==========
  • 打开工程文件中的 src\protogen\bin\Release\net40 文件夹,可得到所有的工具;

  • protobuf-net 还提供了 protogen在线生成脚本工具 ,可以在线校验本地生成结果是否正确。

然而,我出现的问题与这篇中的问题一致 Unity中使用ProtoBuff3.0,与netty服务器通信的粘包、拆包处理(一)

,问题在于:unity支持的.net版本是2.0和3.5,protobuf-net最新支持的是.NET Framework 4.0+的,官网上说v2.1.0的版本支持.NET Framework 2.0/3.0/3.5 ,但是一直安装不成功,不知道是哪里编译设置的问题,干脆就不瞎倒腾了。

protobuf3-for-unity :

所以,最后我也选择使用 protobuf3-for-unity 的方案来实现 C# 层面的协议解析中序列化和反序列化的库:

  • 将编译好的 Google.Protobuf.dll 动态库放在 Assets/Plugins 目录下;

  • 使用 protoc.exe 得到 C# 脚本:protoc --csharp_out=(.cs输出目录) --proto_path=(.proto存放目录) (当前.proto文件名称)

  • 解析示例:

    // 序列化
    TvTEnvironment environment = new TvTEnvironment();
    environment.Id = 20;
    environment.PopulationValue = 66;
    MemoryStream stream = new MemoryStream();
    environment.WriteTo(stream);
    byte[] bytes = stream.ToArray();
    // 反序列化
    TvTEnvironment environment1 = TvTEnvironment.Parser.ParseFrom(bytes);

    假如要使用泛型封装,可以参考下面:

    public static IMessage Deserialize(MessageParser _type,byte[] byteData)
    {
        Stream stream = new MemoryStream(byteData);
        if(stream != null){
            IMessage t = _type.ParseFrom(stream);
            stream.Close();
            return t;
        }
        stream.Close();
        return default(IMessage);          
    }
    public static byte[] Serialize(IMessage _data)
    {
        MemoryStream stream = new MemoryStream();
        if(stream != null){
            _data.WriteTo(stream);
        byte[] bytes = stream.ToArray();
            stream.Close();
            return bytes;
        }
        stream.Close();
        return null;          
    }

    使用泛型接口:

    TvTEnvironment environment = new TvTEnvironment();
    environment.Id = 20;
    environment.PopulationValue = 66;
    // 序列化
    var datas = Serialize(environment);
    // 反序列化
    TvTEnvironment data = (TvTEnvironment)Deserialize(TvTEnvironment.Parser,datas);

参考:

猜你喜欢

转载自blog.csdn.net/linshuhe1/article/details/78326350