Unity中使用ProtoBuf-保姆式教程

·ProtoBuf介绍

ProtoBuf 是结构数据序列化方法,可简单类比于 XML、JSON,其具有以下特点:

  • 语言无关、平台无关。即 ProtoBuf 支持 Java、C++、Python 等多种语言,支持多个平台
  • 高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单
  • 扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序

·ProtoBuf获取

我这边选择的版本为 ProtoBuf 3.5.x

一共需要两个步骤

1.Google.Protobuf

从GitHub上获取完整版 传送门, 选择3.5.x的版本

 这里有2条方式可供选择

 (1)在unity中使用源码

 Google.Protobuf这个文件夹直接放入到unity中

 (2)在unity中使用Google.Protobuf.dll

 使用vs打开它,用release去编译Google.Protobuf这个工程,在release这个目录下你会得到这个dll,放入到你的Libraries中

2.Protoc

从GitHub上获取windows版本 传送门, 选择3.5.1的版本

在bin中找到我们要的protoc.exe

写好 proto 文件之后用 protoc 编译器将 .proto文件编译成目标语言。


·.proto文件

测试文件内容

// 指定版本
syntax = "proto3";
// C#中的namespace
package ProtoTest

option optimize_for = SPEED;

// java文件路径
option java_package = "com.montior.proto";

// java文件名称
option java_outer_classname = "MonitorData";

// 消息结果。
message MsgResult {
    // 结果码。
    int32 code = 1;
    // 错误消息。
    string err_msg = 2;

}

// 接收包
message TaskProtocol {
    // 数据类型
    int32 packType = 1;

    // 具体数据
    bytes content = 3;

}

// 包的类型
enum PackType {
    LOGIN = 0;
    CREATE_TASK = 2;
    DELETE_TASK = 3;
}

message LoginPack{
    string username = 1;
}

message LoginPack2{
    string username = 1;
}

message CreateTaskPack{
    string taskId = 1;
    string taskName = 2;
}
  1. message:消息类型,类似于一个类

  2. package:包名,CSharp中的命名空间,用来防止不同消息类型的冲突

  3. enum:枚举,这个需要我说吗?

  4. option:选项,说明下我这边用到的
    option java_package = “com.example.foo”;// java文件路径
    option java_outer_classname = “Ponycopter”;// java文件名称
    option optimize_for = SPEED;//可以被设置为 SPEED, CODE_SIZE,or LITE_RUNTIME。这些值将通过如下的方式影响C++及java代码的生成:

    注:以上选项,CSharp都用不着的,就是写着玩儿....

  5. 数据类型

    protobuf 数据类型

    描述

    C++

    bool

    布尔类型

    bool

    double

    64位浮点数

    double

    float

    32为浮点数

    float

    int32

    32位整数、

    int

    uin32

    无符号32位整数

    unsigned int

    int64

    64位整数

    __int64

    uint64

    64为无符号整

    unsigned __int64

    sint32

    32位整数,处理负数效率更高

    int32

    sing64

    64位整数 处理负数效率更高

    __int64

    fixed32

    32位无符号整数

    unsigned int32

    fixed64

    64位无符号整数

    unsigned __int64

    sfixed32

    32位整数、能以更高的效率处理负数

    unsigned int32

    sfixed64

    64为整数

    unsigned __int64

    string

    只能处理 ASCII字符

    std::string

    bytes

    用于处理多字节的语言字符、如中文

    std::string

  6. 关键字
    指定字段说明
    required表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置required字段或者无法识别required字段都会引发编解码异常,导致消息被丢弃。
    optional表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。---因为optional字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡。
    repeated表示该字段可以包含0~N个元素。其特性和optional一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。


·在Unity的布局

UnityProject
        -Asset
                --Libraries
                        ---Google.Protobuf        // Protobuf源文件/dll文件

                --Scripts/Editor/Proto2CSEditor        // 放置.proto文件转化为cs的代码
                --Scripts/ProtoMessage        // 放置转化的cs的代码
​​​​        -Proto
                --monitorData.proto        //放置.proto文件
                --protoc.exe                    //

·如何使用protoc.exe把.proto文件转化为.cs

        [MenuItem("Tools/Proto2CS")]
        public static void AllProto2CS()
        {
            string rootDir = Environment.CurrentDirectory;
            string protoDir = Path.Combine(rootDir, "Proto/");

            string protoc;
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                protoc = Path.Combine(protoDir, "protoc.exe");
            }
            else
            {
                protoc = Path.Combine(protoDir, "protoc");
            }

            string hotfixMessageCodePath = Path.Combine(rootDir, "Assets", "Scripts", "ProtoMessage/");

            string argument2 = $"--csharp_out=\"{hotfixMessageCodePath}\" --proto_path=\"{protoDir}\" monitorData.proto";

            Run(protoc, argument2, waitExit: true);

            UnityEngine.Debug.Log("proto2cs succeed!");

            AssetDatabase.Refresh();
        }

        public static Process Run(string exe, string arguments, string workingDirectory = ".", bool waitExit = false)
        {
            try
            {
                bool redirectStandardOutput = true;
                bool redirectStandardError = true;
                bool useShellExecute = false;
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    redirectStandardOutput = false;
                    redirectStandardError = false;
                    useShellExecute = true;
                }

                if (waitExit)
                {
                    redirectStandardOutput = true;
                    redirectStandardError = true;
                    useShellExecute = false;
                }
                
                ProcessStartInfo info = new ProcessStartInfo
                {
                    FileName = exe,
                    Arguments = arguments,
                    CreateNoWindow = true,
                    UseShellExecute = useShellExecute,
                    WorkingDirectory = workingDirectory,
                    RedirectStandardOutput = redirectStandardOutput,
                    RedirectStandardError = redirectStandardError,
                };
                
                Process process = Process.Start(info);

                if (waitExit)
                {
                    process.WaitForExit();
                    if (process.ExitCode != 0)
                    {
                        throw new Exception($"{process.StandardOutput.ReadToEnd()} {process.StandardError.ReadToEnd()}");
                    }
                }

                return process;
            }
            catch (Exception e)
            {
                throw new Exception($"dir: {Path.GetFullPath(workingDirectory)}, command: {exe} {arguments}", e);
            }
        }

·序列化与反序列化

·举个栗子

        MsgResult result = new MsgResult
        {
            Code = -999,
            ErrMsg = "Error"
        };

        TaskProtocol msgResult = new TaskProtocol
        {
            PackType = 111,
            Content = result.ToByteString()
        };

        byte[] s = packer.SerializeTo(msgResult);
        Debug.Log("---------------------------------------------------");


        TaskProtocol response = new TaskProtocol();
        packer.DeserializeFrom(response, s);

        MsgResult responseMsgResult = new MsgResult();
        packer.DeserializeFrom(responseMsgResult, response.Content.ToByteArray());

        Debug.Log(response.PackType);
        Debug.Log(responseMsgResult.Code);
        Debug.Log(responseMsgResult.ErrMsg);

·Unity中还可以使用protobuf-net.dll

<!--暂无-->

·结语

如果这样你都还配置不好ProtoBuf,不知道怎么序列化和反序列化的话!!!!

那就多看几遍,哈哈哈

### 回答1: b'unity protobuf-net' 是指在 Unity 引擎使用 protobuf-net 库进行数据序列化和反序列化的操作。protobuf-net 是一种高效、跨平台的二进制序列化格式,可以将数据对象转换成二进制数据流,方便进行网络传输和存储。在 Unity 使用 protobuf-net 可以提高数据传输和存储的效率,同时也可以提高游戏的性能。 ### 回答2: Unityprotobuf-net是两个不同的技术,但它们可以结合使用Unity是一款流行的游戏引擎,可以用来制作2D和3D游戏。它提供了许多游戏开发所需的功能和工具,例如渲染引擎、物理引擎、动画系统和网络功能等。Unity还可以在多个平台上运行,包括PC、移动设备和虚拟现实头显等。 Protobuf-net是一个开源的C#库,用于序列化和反序列化数据。它可以将对象序列化为二进制数据,并将其保存到文件或通过网络传输。另外,protobuf-net还可以将二进制数据反序列化为对象。protobuf-net的优点是序列化和反序列化速度非常快,并且生成的二进制数据量小,适合于网络传输。 在Unity,我们可以使用protobuf-net来序列化和反序列化游戏对象。这种方法可以提高游戏的性能和效率,因为protobuf-net生成的二进制数据比其他格式(例如JSON)要更小,并且可以更快地发送到其他玩家或服务器。此外,protobuf-net还可以将数据序列化为可序列化的二进制文件,以供使用。 总结来说,Unityprotobuf-net都是非常有用的技术,结合使用可以提高游戏的性能和可扩展性。如果您正在进行Unity游戏开发并且需要高效的网络传输和数据交换方式,请考虑使用protobuf-net来处理游戏数据。 ### 回答3: Unity是一个强大的游戏引擎,它提供了许多工具和技术来帮助游戏开发者快速开发和部署游戏应用程序。Protobuf-net是一个基于Google的Protocol Buffers协议的.NET库,它能够在Unity帮助处理序列化和反序列化问题。 Protobuf-net是一个非常流行的序列化和反序列化库,它使用了一种高效、紧凑的二进制格式,能够在数据传输和存储实现高效率和高速度。在Unity项目使用Protobuf-net可以帮助减少网络传输和存储的负担,提升游戏的性能和响应速度。 在Unity使用Protobuf-net,需要安装相应的库和扩展组件。安装完成后,可以使用C#语言来进行序列化和反序列化操作。Protobuf-net能够兼容多种平台和操作系统,包括Windows、Linux、Mac OS等,同时也能够支持多种数据类型和格式,例如JSON、XML等。 总之,利用UnityProtobuf-net的组合可以帮助提升游戏的性能和响应速度,从而提高游戏玩家的体验。但是,在使用Protobuf-net时,需要注意一些细节,例如数据类型的转换、版本的兼容性等问题,以确保数据的安全和可靠性。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jerrt-J

希望我创作能给你带来有用的帮助

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值