《Unity 3D遊戲客戶端基礎框架》protobuf 導excel表格資料
前言:
之前使用NPOI外掛編寫的導表工具,其實就是直接將資料進行序列化,解析時還需要進行反序列化,步驟比較繁複,最近看到Google的一個開源的專案protobuf,不僅可以用於進行excel表格資料的匯出,還能直接用於網路通訊協議的定製。
一、protobuf簡介:
protobuf是由google公司釋出的一個開源的專案,是一款方便而又通用的資料傳輸協議。所以我們在Unity中也可以藉助protobuf來進行資料儲存和網路協議兩方面的開發,這裡先說說資料儲存部分的操作,也就是:
將.xls表格資料通過protobuf進行序列化,並在Unity中使用
1.下載資源:
2.流程圖:
從上圖可看出基本的操作步驟:
- .xls表格檔案,先通過xls_deploy_tool.py生成對應的.data檔案和.proto檔案,其中.data檔案就是表格資料序列化後的結果,而.proto檔案則是用於生成反序列化時使用的解析類的中間狀態;
- 解析類.proto經過protoc.exe轉換成.desc檔案,用於後面通過protobuf-net等工具轉化為特定的語言,這裡我們需要得到的是C#解析類,即.cs類;
- 在Unity中匯入protobuf-net.dll庫,在C#程式碼中呼叫上述生成的.cs解析類來解析.data中的資料。
二、導表環境配置:
1.Python相關配置:
由於從.xls檔案生成.data和.proto,Python需要依賴Proto庫和xlrd庫,安裝配置步驟:
- setuptools:這是Python的元件安裝管理器,需要在安裝protobuff元件前進行安裝,到setuptools官網下載外掛的安裝包,解壓到指定目錄,然後使用命令列進入安裝包目錄,執行指令:python setup.py install;
- Protobuff:首先,我們將之前下載好的原始碼包protobuf-2.5.0.zip和編譯包protoc-2.5.0-win32.zip壓縮包解壓到指定目錄,路徑最好不要包含中文;
- 這裡我解壓protobuf-2.5.0.zip到的位置是“
- 然後複製protoc-2.5.0-win32.zip解壓得到的protoc.exe到protobuf_250\src目錄下;
- 在protobuf-2.5.0\python\google\protobuf下建立一個資料夾命名為compiler(安裝完成後會在此目錄下生成兩個檔案__init__.py和plugin_pb2.py);
- 使用命令列進入到解壓後的目錄下面的Python目錄,執行:python setup.py install;
- xlrd(xls reader):這其實是讀取xls表格資料的一個工具外掛,到xlrd官網下載xrld的安裝包,解壓安裝包然後使用命令列進入安裝包目錄,執行指令:python setup.py install。
2.導表外部工具:
- xls_deploy_tool.py:這個工具其實是github上的一個開源的符合protobuff標準的根據excel自動生成匹配的PB的定義(.proto檔案)並將資料序列化後生成二進位制資料或者文字資料(.data檔案)的一個工具,github下載地址:xls_deploy_tool.py。
- protoc.exe和protogen.exe:通過上面的工具,我們得到了兩個檔案:儲存資料的.data檔案和用於解析資料的.proto檔案,但是我們在真正使用解析類來進行資料檔案的解析時,必須是高階語言,當然protobuf-net提供很多種高階語言的支援。就像我們在Unity中我們使用的是C#語言,這需要兩個工具來實現,一個是protobuf-2.5.0中的protoc.exe將.proto檔案轉換為“FileDescriptorSet”中間格式;另一個是使用protobuf-net中的protogen.exe,將中間格式的檔案轉換為最終狀態,即高階語言的解析類.cs檔案。
- 可以到github上下載protobuf-net的原始碼:protobuf-net,下載後解壓到本地,然後進入到解壓後protobuf-net-master\protobuf-net目錄下,通過Visual Studio開啟protobuf-net.csproj:
- 編譯完成後在當前目錄下面的bin\Release目錄下,生成了編譯後的檔案,其中我們需要的是protobuf-net.dll:
- 將protobuf-net.dll複製到protobuf-net-master\ProtoGen目錄下,用Visual Studio開啟ProtoGen.csproj,參照上面步驟編譯ProtoGen專案,得到protobuf-net-master\ProtoGen\bin\Release目錄下面的protogen.exe及一些額外的檔案,但在真正使用時此目錄下面的所有檔案都是必須的:
三、樣例:
1.建立表格.xls:
當然使用此工具進行導表的表格需要符合指定的格式,根據xls_deploy_tool.py的備註內容:
# 說明:
# excel 的前四行用於結構定義, 其餘則為資料,按第一行區分, 分別解釋:
# required 必有屬性
# optional 可選屬性
# 第二行: 屬性型別
# 第三行:屬性名
# 第四行:註釋
# 資料行:屬性值
# repeated 表明下一個屬性是repeated,即陣列
# 第二行: repeat的最大次數, excel中會重複列出該屬性
# 2011-11-29 做了修改 第二行如果是型別定義的話,則表明該列是repeated
# 但是目前只支援整形
# 第三行:無用
# 第四行:註釋
# 資料行:實際的重複次數
# required_struct 必選結構屬性
# optional_struct 可選結構屬性
# 第二行:結構元素個數
# 第三行:結構名
# 第四行:在上層結構中的屬性名
# 資料行:不用填
# 1 | required/optional | repeated | required_struct/optional_struct |
# | ------------------| ---------:| ---------------------------------:|
# 2 | 屬性型別 | | 結構元素個數 |
# 3 | 屬性名 | | 結構型別名 |
# 4 | 註釋說明 | | 在上層結構中的屬性名 |
# 5 | 屬性值 | | |
當然可以參考github上下載到的樣例表格,下載tnt專案,然後複製其中python目錄下面的內容,其中xls檔案中就有一個goods_info.xls的樣例表格:
2.xls_deploy_tool.py轉換得到.data和.proto:
進行導表的操作只需用在命令列中的一句指令即可完成:
python xls_deploy_tool.py sheet_name xls_path
其中包含兩個引數:sheet_name是.xls中要進行導表的表格頁名,xls_path是要進行導表的.xls檔案的路徑。建立一個測試工程Test_protobuf,將1中的兩個檔案和protoc.exe放入其中:
在命令列定位到該目錄下,然後執行指令:
call python xls_deploy_tool.py GOODS_INFO xls/goods_info.xls
執行結束後,該目錄下多出了幾個檔案,但我們真正需要的只有兩個檔案,即.data資料檔案和.proto解析類:
3.得到最終解析類:
protoc.exe得到中間格式檔案,假設字尾為.protodesc,使用指令:
protoc 輸入檔案路徑(.proto檔案) --descriptor_set_out=輸出檔案路徑(.protodesc)
在步驟2中的測試工程基礎上繼續執行指令:
protoc tnt_deploy_goods_info.proto --descriptor_set_out=goods_info.protodesc
執行此步之後,在專案中又多出了一個與.proto對應的.protodesc檔案:
protogen.exe得到.cs解析類,使用指令:
protogen -i:輸入檔案路徑(.protodesc) -o:輸出檔案路徑(.cs)
將之前生成protogen.exe時protobuf-net-master\ProtoGen\bin\Release目錄下面的所有檔案複製到當前工程中,用一個資料夾ProtoGen來存放,假如不想執行這麼繁瑣的過程,也可以直接使用我編譯好的ProtoGen檔案目錄壓縮包:ProtoGen.zip,在當前專案的根目錄下執行以下指令:
call ProtoGen\protogen -i:goods_info.protodesc -o:goods_info.cs
執行結果,在當前目錄下生成了解析類的最終狀態goods_info.cs:
當然,以上三步可以直接用批處理來完成,直接在當前專案根目錄下新建一個檔案,命名為generator.bat,內容為:
call python xls_deploy_tool.py GOODS_INFO xls/goods_info.xls
call protoc tnt_deploy_goods_info.proto --descriptor_set_out=goods_info.protodesc
call ProtoGen\protogen -i:goods_info.protodesc -o:goods_info.cs
pause
直接雙擊此檔案即可完成以上所有操作生成最終的.data和.cs檔案。
4.Unity匯入庫檔案:
將幾個檔案新增到Unity工程中,將.data檔案放在Assets\StreamingAssets\DataConfig目錄下,將protobuf-net.dll和goods_info.cs放在Assets目錄下:
建立一個Test.cs測試指令碼,在指令碼中using Protobuf用於匯入protobuf-net.dll中的庫,然後使用using tnt_deploy匯入導表生成的.cs表格資料解析類,指令碼具體程式碼內容為:
using UnityEngine;
using System.Collections;
using ProtoBuf;
using System.IO;
using tnt_deploy;
public class Test : MonoBehaviour {
void Start () {
GOODS_INFO_ARRAY goods_infos = ReadOneDataConfig<GOODS_INFO_ARRAY>("goods_info");
Debug.Log("goods_id==================" + goods_infos.items[0].goods_id);
}
private T ReadOneDataConfig<T>(string FileName)
{
FileStream fileStream;
fileStream = GetDataFileStream(FileName);
if (null != fileStream)
{
T t = Serializer.Deserialize<T>(fileStream);
fileStream.Close();
return t;
}
return default(T);
}
private FileStream GetDataFileStream(string fileName)
{
string filePath = GetDataConfigPath(fileName);
if (File.Exists(filePath))
{
FileStream fileStream = new FileStream(filePath, FileMode.Open);
return fileStream;
}
return null;
}
private string GetDataConfigPath(string fileName)
{
return Application.streamingAssetsPath + "/DataConfig/" + fileName + ".data";
}
}
在Unity中新建一個場景,將Test.cs掛載在Main Camera主相機上,執行場景,看到列印結果,說明解析表格資料成功:
5.平臺相容問題:
由於直接把protobuf-net.dll放到專案中時,在iOS中會出現JIT錯誤(ExecutionEngineException: Attempting to JIT compile method)。原因是因為iOS不允許JIT(Just In Time),只允許AOT(Ahead Of Time)。
解決方法:
直接把protprotobuf-net-master\protobuf-net目錄下面的全部原始碼複製到Unity專案的目錄下面,但是由於protobuf-net的編譯過程是unsafe編譯,所以Unity會出現編譯報錯:
需要在Assets目錄下新增一個smsc.rsp檔案,其內容很簡單,只有一行“-unsafe”,新增完成後關閉Unity然後重新開啟Unity,一切就正常了。
四、總結:
雖然導表環境的配置過程比較繁瑣,但是配置完成之後的工作效率卻很高,而且proto具有突出的通用性,可以應用於各種語言環境。