Unity3D遊戲開發之反編譯AssetBundle提取遊戲資源,unity3dassetbundle
各位朋友,大家好,歡迎大家關注我的部落格,我是秦元培,我的部落格地址是http://www.qinyuanpei.com。今天我們來說說通過反編譯Unity3D的AssetBundle來提取遊戲資源,博主寫這篇文章的目的並非是要教大家如何去破解一款基於Unity3D引擎開發的遊戲,而是想通過今天這篇文章來告訴大家如何在開發Unity3D遊戲的過程中保護自己的遊戲資源。
漫話Unity3D的AssetBundle
對於AssetBundle,其實博主是在以前的文章中是有提到的。不知道大家還記不記得,博主曾經在寫遊戲開發和Lua的不解之緣這個系列文章的時候,提到並且使用過AssetBundle這種技術。具體來說呢,AssetBundle在Unity3D中是一種用於資源打包盒資源動態載入的解決方案,比如我們平時玩的單機遊戲容量一般都比較大,這是因為製作人員在製作遊戲的時候將所有的項目資源都整合到了一起。可是如果我們用AssetBundle來做這個遊戲的話,我們就可以只在發布的遊戲中提供支援遊戲功能的核心部分,而將遊戲當中的情境、模型等資源以AssetBundle的形式打包然後放到伺服器上,這樣當遊戲用戶端處於連網的時候就可以從伺服器上下載這些資源,從而實現遊戲資源的動態載入,由此可見AssetBundle可以協助我們減少遊戲的容量。如果是在需要安裝包的場合下,那麼遊戲包容量的大小無疑會為遊戲加些印象分。
比如最近《軒轅劍6外傳穹之扉》這部單機遊戲發布了,從各大遊戲網站的評測到和一樣我喜歡單機遊戲的各位朋友們的親身體驗,大家一致的認為這部遊戲整體表現還不錯,應該考慮玩一玩。這樣難免讓博主有些心動,可是看到17個G的遊戲容量時還是猶豫了下。DOMO小組從《軒轅劍6》就開始使用Unity3D引擎,在經曆了第一部遊戲的失敗後,或許此次DOMO小組會將遊戲最佳化的比較好吧。這裡如果有喜歡單機遊戲的朋友不妨去玩玩看,畢竟我們學習遊戲開發的初衷就是做出好遊戲,如果不熱愛遊戲又怎麼能做出好遊戲呢?好了,扯得有點遠了,這裡我們注意到一個重要的因素就是遊戲容量,如果DOMO採用AeestBundle的話,遊戲的容量肯定會減少很多。可是這樣一來,它就不是單機遊戲了嘛,對吧!
在Unity3D中AssetBundle是專業版中的一個功能,在免費版的Unity3D中是無法使用這個功能的,不知道在Unity5中這個功能是不是劃分到了個人版中。好了,下面我們來看看如何使用AssetBundle。我們主要從使用AssetBundle打包和載入AssetBundle這兩個方面來說:
使用Assetbundle打包
使用AssetBundle打包主要通過BuildPipeline.BuildAssetBundle()這個方法來實現,該方法原型為:
bool BuildAssetBundle (Object mainAsset,Object[] assets,string pathName, BuildAssetBundleOptions optionsBuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,BuildTarget targetPlatform= BuildTarget.WebPlayer)
在這個方法中,第一個參數是一個Object類型,表示一個啟用的物體;第二個參數是一個Object[]類型,表示所有選中的物體;第三個參數是一個string類型,表示要匯出的資源套件的路徑,資源套件的副檔名可以是assetbundle或者unity3d;第四個參數表示的是打包選項,預設是完全打包和依賴打包。這裡重點解釋下這兩個概念,完全打包是指所有資源都參與打包,比如說一個模型帶有貼圖和動畫,那麼打包模型的時候貼圖和動畫都會被作為資源打包。而依賴打包是相對於Prefab來說的,比如說PrefabA中引用了PrefabB這個對象,那麼打包的時候這兩個對象都會被打包,並且它們之間的這種依賴關係會在打包後繼續保持;第五個參數是平台的選擇,因為Unity3D是一個跨平台的遊戲引擎,而各個平台現在的情況又不盡相同,因此現在Unity3D採取的方案是各個平台只能使用自己平台對應的AssetBundle,這一點希望大家在使用的時候注意啊。好了,現在我們來看一個簡單的例子:
/// <summary> /// 輸出AssetBundle /// </summary> /// <param name="type">平台類型</param> static void ExportToAssetBundle(ExportType type,BuildTarget target) { //擷取儲存路徑 string savePath=EditorUtility.SaveFilePanel("輸出為AssetBundle","","New Resource","unity3d"); if(savePath==string.Empty) return; //擷取選中的對象 Object[] selection=Selection.GetFiltered(typeof(Object),SelectionMode.DeepAssets); if(selection.Length==0) return; //打包 if(type==ExportType.All){ BuildPipeline.BuildAssetBundle(null,selection,savePath,BuildAssetBundleOptions.CollectDependencies,target); }else{ BuildPipeline.BuildAssetBundle(obj,null,savePath,BuildAssetBundleOptions.CollectDependencies,target); } }
這是一個簡單的匯出AssetBundle資源套件的方法,它有兩個參數,第一個參數表示是一個枚舉類型,定義為ExportType,取Single時表示打包一個特定的啟用物體,比如說一個模型、一個情境等等;取All時表示打包所有選中的物體,比如一個情境。第二個參數表示打包的平台,這個不用多說了。因為博主的免費版的Unity3D不支援AssetBundle,所以這裡沒法給大家示範了,具體效果請自行測試,有問題的話給博主留言就是了。
載入AssetBundle
載入AssetBundle是一個從網路中下載資源的過程,因此需要使用Unity3D的WWW功能,這是一個簡單的網路通訊協定的封裝,可以像瀏覽器一樣訪問某個URL地址或者是本地地址,訪問WEB地址需要使用HTTP協議,訪問本地地址需要使用File協議。我們來看一個具體的例子:
/// <summary> /// 載入一個unity3d格式的檔案 /// WEB地址——http://server.com/xxx.unity3d /// 本地地址——file://.unity3d檔案的絕對路徑 /// </summary> IEnumerator LoadUnity3DFile(string url) { WWW www=new WWW(url); yield return www; if(www.error!=null){ Debug.Log(www.error); }else{ AssetBundle bundle=www.assetBundle; Instantiate(bundle.mainAsset,Vector3.zero,Quaternion.identity); } }
在這裡我們直接使用bundle.assetBundle擷取了全部的資源,如果只需要擷取資源中的一部分,則只需要通過bundle.Load()方法就可以了,這裡需要傳入資源的名稱。當我們使用完資源後可以通過bundle.Unload()方法來卸載資源,達到釋放記憶體的目的。
從反編譯《新仙劍OL》看AssetBundle打包
好了,下面我們以《新仙劍OL》這款遊戲的AssetBundle的反編譯來探索下在使用AssetBundle打包應該注意哪些問題。《新仙劍OL》這款遊戲呢,是採用Unity3D引擎開發的一款橫跨用戶端遊戲和網頁遊戲的網路遊戲,遊戲以《仙劍奇俠傳》初代遊戲劇情為主,玩家將第三人稱視角再次跟隨主人公展開一段蕩氣迴腸的感人故事。這款遊戲總體來說還不錯吧,因為畢竟是網遊,我們不能用單機遊戲的視角去評價,具體的原因大家都是知道的。
好了,為什麼我們要選擇這款遊戲呢?
* 第一,這款遊戲的用戶端只有30餘M,體積小適合拿來研究(這就是AssetBundle的好處啊)* 第二,博主是一位仙劍玩家,一直希望有一天《仙劍奇俠傳1》能夠用3D技術重現,這個遊戲滿足了博主的好奇心
* 第三,網路上已經有朋友對這個遊戲的打包進行了研究,這裡感謝網友朋友提供部分.unity3d檔案及相關檔案。
我們選擇的解包工具是一款叫做disunity的命令列工具,經過博主的嘗試,這個工具真心強悍啊,可以解開.unity3d檔案和.assets檔案,可以拿到的資料形式有貼圖、聲音、模型等。具體的情況大家可以在稍後看到。
首先我們找到《新仙劍OL》的安裝目錄,然後我們就能發現一個叫做assetbundles的檔案夾,這是怕大家不知道嗎?這太明顯了吧!我們開啟檔案夾會發現Charachers、NPC、Scene等等檔案夾,繼續往下找我們發現了好多的.unity3d檔案,不過這些檔案都是以.unity3d然後跟些隨機字串的形式存在的。根據網友朋友們的提示,這些檔案就是.unity3d檔案,不過遊戲製作組為了幹擾我們故意接了下隨機字元在後面(呵呵,還有比這更弱的加密方式嗎?)。博主看到這裡的第一感覺就是想先用載入AssetBundle的方式來看看能不能將這些AssetBundle讀取出來,因此果斷改了副檔名,然後開始在Unity3D中讀取,結果程式報錯看來是我們想的簡單了啊。沒辦法的辦法,強行解包吧!在命令列中輸入:
disunity extract C:\Users\Robin\Desktop\s049.unity3d
接下來程式會在案頭上產生一個上s049的檔案夾,開啟檔案夾一看,尼瑪,竟然直接拿到了模型的網格資料(.obj)和貼圖資料(.dds)以及相關的Shader。這讓我突然間有點不能接受啊,馬上開啟Blender將網格資料匯入,結果童年的林月如就出現在了我們的面前:
因為博主不會在Blender中給模型貼圖,所以我們到Unity3D中完成貼圖,首先需要將模型匯出為FBX格式。好了,將模型匯入Unity3D後,將貼圖賦給模型,童年的林月如就閃亮登場了,哈哈!
好了,再來一張,不過這張沒有貼圖,需要大家自己來辨別這是誰啊,哈哈!
通過disunity這個工具我們還能擷取更多的資源,剩下的內容就由大家自己去探索吧。通過這部分的研究,我們可以總結出以下觀點,希望大家在使用AsssetBundle這項技術時注意:
* 盡量在一個AssetBundle中打包多個資源,這樣做的好處是別人沒法通過載入AssetBundle拿到你做好的Prefab。
* 盡量將一個預製件分割成不同的部分分別存放,這樣做的好處是即使別人拿到了你的預製件卻是不完整的。
* 盡量利用動態指令碼來載入情境而不是將整個情境打包,即使將整個情境打包,要把貼圖和模型分開放置(因此如此,我雖然拿到了遊戲的情境貼圖,可是沒有用啊)
* 盡量利用加密的方法來隱藏本地的AssetBundle或者使用不易察覺的儲存位置作為AssetBundle的儲存位置,不要用明文資料進行儲存。
好了,今天的內容就是這樣了,希望大家喜歡,AssetBundle打包是一個值得去深入研究的問題,今天博主提出的這些觀點不過是對《新仙劍OL》這個遊戲的打包提出de一些看法,如果大家有不同的看法,歡迎一起來交流!