Unity での ProtoBuf の使用 - nanny チュートリアル

·ProtoBuf の概要

ProtoBuf は、単純にXML や JSON と比較できる構造化データのシリアル化メソッドであり、次の特徴があります。

  • 言語、プラットフォームに依存しませんつまり、ProtoBuf は Java、C++、Python などの言語をサポートし、複数のプラットフォームをサポートします。
  • 効率的ですつまり、XML よりも小さく (3 ~ 10 倍)、高速 (20 ~ 100 倍)、簡単です。
  • 優れた拡張性と互換性元の古いプログラムに影響を与えたり破壊したりすることなく、データ構造を更新できます。

・ProtoBuf取得

ここで選択したバージョンは ProtoBuf 3.5.x です。

合計 2 つの手順が必要です

1.Google.Protobuf

GitHub から完全バージョンのPortalを入手し、バージョン 3.5.x を選択します

 2つの方法から選択できます

 (1) Unityでソースコードを利用する

 Google.Protobuf フォルダーは Unity に直接配置されます

 (2) UnityでGoogle.Protobuf.dllを使用する

 vs を使用して開き、release を使用して Google.Protobuf プロジェクトをコンパイルします。この DLL をリリース ディレクトリに取得し、ライブラリに置きます。

2.プロトック

GitHub から Windows バージョンのポータルを取得し、バージョン 3.5.1 を選択します。

ビン内で必要な 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: オプション、ここで使用するオプションの説明
    java_package = "com.example.foo";//java ファイルパス
    オプション java_outer_classname = "Ponycopter";//java ファイル名
    オプション optimize_for = SPEED;//設定可能 SPEED です、CODE_SIZE、または LITE_RUNTIME。これらの値は、次のように C++ および Java コードの生成に影響します。

    注: 上記のオプションは、CSharp では必要ありません。ただ楽しむためです。

  5. データの種類

    protobuf データ型

    説明

    C++

    ブール

    ブール型

    ブール

    ダブル

    64ビット浮動小数点数

    ダブル

    浮く

    32 は浮動小数点数です

    浮く

    int32

    32ビット整数、

    整数

    uin32

    符号なし 32 ビット整数

    符号なし整数

    int64

    64ビット整数

    __int64

    uint64

    64 は符号なし整数です

    符号なし __int64

    sint32

    32 ビット整数、負の数の処理がより効率的

    int32

    歌う64

    64 ビット整数は負の数をより効率的に処理します

    __int64

    固定32

    32ビット符号なし整数

    符号なし int32

    固定64

    64ビット符号なし整数

    符号なし __int64

    固定32

    32 ビット整数、負の数をより効率的に処理できます

    符号なし int32

    固定64

    64は整数です

    符号なし __int64

    ASCII 文字のみを処理できます

    std::文字列

    バイト

    中国語などのマルチバイト言語文字を処理する場合

    std::文字列

  6. キーワード
    指定されたフィールド 説明する
    必要 必須フィールドであることを示します。送信者を基準とした相対値である必要があります。このフィールドの値は、メッセージを送信する前に設定する必要があります。受信者は、このフィールドの意味を認識できる必要があります。必須フィールドが設定されていない場合、または送信前に必須フィールドが認識できない場合は、コーデック例外がスローされ、メッセージは破棄されます。
    オプション オプション 送信者は、メッセージを送信するときに、このフィールドの値を選択的に設定するかどうかを選択できます。受信側では、オプションのフィールドが認識できれば、それに応じて処理されますが、認識できなければ、そのフィールドは無視され、メッセージ内の他のフィールドは通常どおり処理されます。---オプション フィールドの特性により、多くのインターフェイスでは、追加されたフィールドをアップグレード バージョンのオプション フィールドとして一律に設定するため、古いバージョンではプログラムをアップグレードすることなく新しいソフトウェアと正常に通信できますが、新しいフィールドでは通信できません。すべてのノードが新しい機能を必要とするわけではないため、オンデマンドのアップグレードとスムーズな移行を実現できます。
    繰り返された フィールドに 0 ~ N 個の要素を含めることができることを示します。その特性はオプションと同じですが、毎回複数の値を含めることができます。値の配列を渡すと見なすことができます。


· 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);

・Protobuf-net.dllはUnityでも使用可能

<!--今のところなし-->

・結論

まだ ProtoBuf をうまく設定できず、シリアル化および逆シリアル化する方法がわからない場合は、

それから、もう何回か見てください、ハハハ

おすすめ

転載: blog.csdn.net/flj135792468/article/details/119970151