当前位置:   article > 正文

Unity | 集成 Protobuf(proto 转 cs 插件及序列化与反序列化)_proto导出cs

proto导出cs

1. 添加 dll

1. 下载 protobuf 源码

根据需要下载 protobuf 指定版本的源码,这里以 v3.21.12(protobuf-csharp-3.21.12.zip)为例:

下载地址:「https://github.com/protocolbuffers/protobuf/releases」

2. 下载 Visual Studio 2022

曾尝试使用 Visual Studio 2021 版本编译,但是会报错,更新版本后,即可编译成功

下载地址:「https://visualstudio.microsoft.com/zh-hans/downloads/」

3. 编译 dll

1. 使用 Visual Studio 2022 打开 protobuf 项目中的 Google.Protobuf.sln

2. 编译模式选择:Release

3. Google.Protobuf 右键选择生成 Google.Protobuf

4. 拷贝 dll

编译生成的 dll 在 csharp/src/Google.Protobuf/bin/Release 目录下

将 net45 目录下所有的 dll 文件拷贝到 Unity 指定目录中

2. proto 转 cs

1. 下载编译器

在 protobuf 源码链接中下载对应的平台的编译器(mac: protoc-21.12-osx-x86_64.zip,windows:protoc-21.12-win64.zip)

2. 命令行转换

在终端中进入到编译器所在的目录:bin/protoc,然后执行对应的命令

  • 转换指定 proto 文件:

./protoc ./Addressbook.proto --csharp_out=./
  • 转换指定目录下所有 proto 文件:

./protoc ./*.proto --csharp_out=./

将生成的 cs 文件,放入 Unity 项目中

3. 插件转换

除了直接使用命令行外,也可以在 Unity 中编写插件,利用 Process 执行命令行,转换 proto 文件:

  1. public class ProtoToClass
  2. {
  3.     [MenuItem("RavenKit/Proto To Class")]
  4.     public static void GenerateClassFromProto()
  5.     {
  6.         string rootPath = Environment.CurrentDirectory;
  7.         string protoPath = Path.Combine(rootPath, "Proto/");
  8.         string protoc = Path.Combine(protoPath,
  9.             RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "protoc.exe" : "protoc");
  10.         string outPath = EditorPrefs.GetString(Application.identifier + "-ProtoClassPath");
  11.         if (string.IsNullOrEmpty(outPath))
  12.         {
  13.             outPath = EditorUtility.OpenFolderPanel("选择存储目录", Application.dataPath, "");
  14.             if (!string.IsNullOrEmpty(outPath))
  15.             {
  16.                 EditorPrefs.SetString(Application.identifier + "-ProtoClassPath", outPath);
  17.             }
  18.         }
  19.         string[] protoFiles = Directory.GetFiles(protoPath, "*.proto");
  20.         foreach (var variable in protoFiles)
  21.         {
  22.             string argument = $"--csharp_out={outPath} --proto_path={protoPath} {variable}";
  23.             Run(protoc, argument);
  24.         }
  25.         AssetDatabase.Refresh();
  26.     }
  27.     public static Process Run(string exe, string arguments)
  28.     {
  29.         ProcessStartInfo info = new ProcessStartInfo
  30.         {
  31.             FileName = exe,
  32.             Arguments = arguments,
  33.             CreateNoWindow = true,
  34.             UseShellExecute = false,
  35.             RedirectStandardOutput = true,
  36.             RedirectStandardError = true,
  37.         };
  38.         Process process = Process.Start(info);
  39.         process.WaitForExit();
  40.         if (process.ExitCode != 0)
  41.         {
  42.             Debug.LogError($"Failed to Run {arguments}. Exit code: " + process.ExitCode);
  43.         }
  44.         return process;
  45.     }
  46. }

3. 序列化及反序列化

使用方法在官方的源码中也有详细的示例:

  1. byte[] bytes;
  2. // Create a new person
  3. Person person = new Person
  4. {
  5.     Id = 1,
  6.     Name = "Foo",
  7.     Email = "foo@bar",
  8.     Phones = { new Person.Types.PhoneNumber { Number = "555-1212" } }
  9. };
  10. using (MemoryStream stream = new MemoryStream())
  11. {
  12.     // Save the person to a stream
  13.     person.WriteTo(stream);
  14.     bytes = stream.ToArray();
  15. }
  16. Person copy = Person.Parser.ParseFrom(bytes);
  17. AddressBook book = new AddressBook
  18. {
  19.     People = { copy }
  20. };
  21. bytes = book.ToByteArray();
  22. // And read the address book back again
  23. AddressBook restored = AddressBook.Parser.ParseFrom(bytes);
  24. // The message performs a deep-comparison on equality:
  25. if (restored.People.Count != 1 || !person.Equals(restored.People[0]))
  26. {
  27.     throw new Exception("There is a bad person in here!");
  28. }

反序列化时,除了使用 ParseFrom 方法

AddressBook.Parser.ParseFrom(bytes) 

也可以使用 MergeFrom 方法

message.MergeFrom(data);

将序列化和反序列化封装为通用的函数:

  1. public static class ProtobufUtility
  2. {
  3.     /// <summary>
  4.     /// 序列化
  5.     /// </summary>
  6.     /// <param name="msg"></param>
  7.     /// <returns></returns>
  8.     public static byte[] Serialize(IMessage message)
  9.     {
  10.         using (MemoryStream stream = new MemoryStream())
  11.         {
  12.             message.WriteTo(stream);
  13.             byte[] result = ms.ToArray();
  14.             return result;
  15.         }
  16.     }
  17.     /// <summary>
  18.     /// 反序列化
  19.     /// </summary>
  20.     /// <typeparam name="T"></typeparam>
  21.     /// <param name="data"></param>
  22.     /// <returns></returns>
  23.     public static T Deserialize<T>(byte[] data) where T : IMessage, new()
  24.     {
  25.         T message = new T();
  26.         // message = (T)message.Descriptor.Parser.ParseFrom(data);
  27.         message.MergeFrom(data);
  28.         return msg;
  29.     }
  30. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/720059
推荐阅读
相关标签
  

闽ICP备14008679号