1. 程式人生 > >Unity實戰之Protobuf案例應用

Unity實戰之Protobuf案例應用

轉自https://blog.csdn.net/jxw167/article/details/80127696

Protobuf 全稱Protocol Buffers 是一種輕便高效的結構化資料儲存格式,可以用於結構化資料序列化,很適合做資料儲存或 RPC 資料交換格式。它可用於通訊協議、資料儲存等領域的語言無關、平臺無關、可擴充套件的序列化結構資料格式。目前提供了 C++、Java、Python、C#等多種語言的 API。Protobuf是google開源的序列化和反序列化工具,主要是用在網路遊戲的訊息結構體定義上。它相對於XML檔案和Json檔案效能更好,效率更高,在在網站 http://code.google.com/p/protobuf/downloads/list上可以下載 Protobuf 的原始碼,它的檔案格式是以.proto為副檔名的檔案。為了便於大家更好的理解其使用原理,下面就通過案例的方式給大家講解。
1Protobuf訊息結構體定義 
    在使用Protobuf定義訊息結構體時首先要搞明白其語法結構,Protobuf定義的訊息由至少一個欄位組合而成,類似於C語言中的結構。每個欄位都有一定的格式。其限定修飾required、optional、repeated三個修飾符。 
Required修飾符表示是一個必須欄位,必須相對於傳送方,在傳送訊息之前必須設定該欄位的值,對於接收方,必須能夠識別該欄位的意思。傳送之前沒有設定required欄位或者無法識別required欄位都會引發編解碼異常,導致訊息被丟棄。 
Optional修飾符表示是一個可選欄位,可選對於傳送方,在傳送訊息時,可以有選擇性的設定或者不設定該欄位的值。對於接收方,如果能夠識別可選欄位就進行相應的處理,如果無法識別,則忽略該欄位,訊息中的其它欄位正常處理。—因為optional欄位的特性,很多介面在升級版本中都把後來新增的欄位都統一的設定為optional欄位,這樣老的版本無需升級程式也可以正常的與新的軟體進行通訊,只不過新的欄位無法識別而已,因為並不是每個節點都需要新的功能,因此可以做到按需升級和平滑過渡。 
Repeated:表示該欄位可以包含0~N個元素。其特性和optional一樣,但是每一次可以包含多個值,可以看作是在傳遞一個數組的值或者List列表數值。開發網路遊戲時,經常會定義訊息結構體,這些訊息結構體會在客戶端和伺服器中都會用到,所以只需要定義一套就可以了,現在移動端大部分使用者都在使用Unity引擎開發,所以這些結構體需要轉成C#語言。下面開始從結構體定義開始講起。 
編寫Protobuf結構體 
    網路訊息的定義通常會使用json檔案或者二進位制檔案或者自定義結構體,現在使用protobuf定義訊息結構體的公司越來越多,逐漸成為訊息結構體定義的主流,這也要感謝google提供了一個開源的序列化和反序列化工具。本節以實際專案開發的案例給大家介紹一下網路訊息結構體的定義,任何大型網路遊戲都有角色的定義。首先從角色的定義說起,角色訊息包括很多的屬性。定義結構體如下所示,其中message是結構體的修飾符,是必須的。結構體定義如下所示: 
//角色資訊結構message msgcharinfo
{
    optional uint32 uaid = 1;    //使用者ID
    optional uint32 charid = 2;  //角色ID
    optional uint32 kind = 3; //角色種類
    optional string name = 4;  //角色名字
    optional string head = 5;   //頭像ID
    optional uint32 level = 6;  //角色等級
    optional uint32 exp = 7;  //角色經驗
    optional uint32 phypower = 8;   //物理攻擊
    optional uint32 leadership = 9;  //領導標記
    optional uint32 friendnum = 10;   //朋友數量
    optional uint32 gamecoin = 11;   //遊戲貨幣
    optional uint32 diamond = 12;  //鑽石數量
};123456789101112131415以上是網路遊戲中完整的角色定義,包括使用者id,遊戲中角色id等資訊。它存放的副檔名為.proto。結構體中的各個項的修飾都是optional,也就是可選項,可以不用賦值。protobuf自身定義的檔案是文字檔案。如果將該檔案直接放到Unity工程中,Unity是不會識別的。這就需要將其轉成Unity可識別的腳步C#檔案。再舉一個例子,還是結構體定義是列舉定義程式碼如下所示: 
//初始化角色獎勵資訊enum enumGetCharRewardResult
{
    Success  = 0;           //成功獲取角色
    SystemError = 1;        //系統錯誤
    NewChar = 2;            //建立新角色獎勵資訊
};123456該結構體是以enum修飾的列舉型別,裡面有三項,列舉定義跟C++或者Java定義的類似,列舉定義的內部成員不需要任何符號修飾。假設以上內容是在檔案common.proto檔案定義的,下面我們再定義一個proto檔案,其內容如下所示:
1package clientmsg;
import "common.proto";
message C2SNameRepetition
{
    optional msgcharinfo charinfo = 1;    //建立角色
    optional uint32 mapid = 2;
    optional uint32 cityid = 3;
};12345678給大家解釋一下程式碼,第一行package clientmsg;表示的是模組的封裝,其含義類似C++或者C#的namespace名稱空間,第二行import "common.proto";表示的是引用該檔案,目的是需要用到該檔案已定義的結構體,例如message C2SNameRepetition定義的內容中的語句optional msgcharinfo charinfo = 1;它引用的是common.proto檔案中已定義的msgcharinfo的結構體,protobuf支援這種引用關係,從中可以看出Protobuf語言也是比較靈活的,檔案與檔案之間是可以互相引用的,接下來開始介紹轉換工具的製作了。
1Protobuf轉換工具製作 
    定義好了proto檔案後,如果直接放到unity中,它只能被作為文字檔案,這不是開發者想要的,因為要在程式中使用定義好的結構體,需要一個能將其轉換成C#指令碼檔案的工具。下面開始告訴大家制作該工具需要做哪些工作?製作工具需要的庫檔案可以在網上下載到,就是已編譯好的庫工程,主要內容如下圖所示: 接下來需要寫一個批處理檔案執行proto批量轉換操作,假設上述庫檔案是在檔案路徑:3Party\protobuf-net\net下面。製作的工具檔案的副檔名為.bat。批處理檔案完整內容如下所示:

[email protected] off
set tool=..\3Party\protobuf-net\net

rem ===============================================
rem  Support
set proto=common.proto
%tool%\protogen.exe -i:%proto% -o:%proto%.cs -q

set proto=login.proto
%tool%\protogen.exe -i:%proto% -o:%proto%.cs -q

set proto=begingame.proto
%tool%\protogen.exe -i:%proto% -o:%proto%.cs -q
pause1234567891011121314其中語句set tool=..\3Party\protobuf-net\net表示的是庫檔案所在的目錄,set proto=common.proto表示的是要轉換的proto檔名字,%tool%\protogen.exe -i:%proto% -o:%proto%.cs -q表示的是呼叫上述目錄下的庫,將common.proto轉化成common.proto.cs檔案,以此類推,因為我們定義的commo.cs是公用的檔案,下面的檔案都會引用到該檔案的內容,同時把proto檔案拷貝到與副檔名bat相同的資料夾下面。其執行的效果如下圖所示:
1make-protobuf.bat就是執行的批處理程式,執行的結果就是生成對應的cs檔案,然後將cs檔案拖放到Unity的目錄下面,生成的cs檔案內容如下所示,以login.proto.cs檔案為例,檔案內容如下圖4-3所示: 限於篇幅所限,只擷取一部分內容,第一行表示的是引用common,再下面是名稱空間以及類宣告,眼尖的讀者可能注意到了一個細節就是類前面的修飾符partial,給大家介紹一下,它屬於一個區域性型別,區域性型別允許我們將一個類、結構或介面分成幾個部分,分別實現在幾個不同的.cs檔案中。給大家普及一下partial的基礎知識,一是型別特別大,不宜放在一個檔案中實現;二是一個型別中的一部分程式碼為自動化工具生成的程式碼,不宜與我們自己編寫的程式碼混合在一起;三是需要多人合作編寫一個類。這幾種情況適用於partial修飾。接下來介紹一下如何在Unity中使用。 
Protobuf檔案在Unity中運用 
    在Unity中使用定義的Protobuf檔案,首先需要把Protobuf-net的原始檔放到Unity目錄下,原始檔的下載地址是: https://github.com/mgravell/protobuf-net/tree/master/protobuf-net,使用原始檔的目的是可以實現Protobuf在android和ios平臺同時使用,程式碼可以直接在Google提供的官網上直接下載,拖放到Unity中的效果如下圖4-4所示 這些前期工作完成後就可以直接呼叫Protobuf原始碼中的庫函式進行序列化和反序列化。下面將生成的cs指令碼檔案拖放到Unity中,效果如下圖所示:
1接下來介紹一下如何在Unity中使用,在使用定義好的結構體時,需要在檔案中加入引用標頭檔案的using clientmsg,然後在函式中首先new一個物件如下所示:   
1clientmsg.c2s_login msg = new clientmsg.c2s_login();1然後再對其結構體填充數值,如下語句所示:    msg.name = Global.userInputName;
        msg.pwd = Global.password;
        messageContentLen += msg.name.Length;
        messageContentLen += msg.pwd.Length;1234最後可以將其結構體傳送到伺服器:SendProtoBufMsg(msg, awnet);這樣整個Protobuf檔案的使用就結束了,希望對大家有所幫助,具體詳情檢視書籍《Unity3D實戰核心技術詳解》一書。
1筆者簡介:姜雪偉個人網頁
--------------------- 
作者:海洋_ 
來源:CSDN 
原文:https://blog.csdn.net/jxw167/article/details/80127696 
版權宣告:本文為博主原創文章,轉載請附上博文連結!