U3D的AssetBundle真的是博(坑)大精(坑)深啊
安卓的話要先打包到StreamingAssetPath中,安裝後第一次運行,自動把Streaming 中的解壓到PersistentDataPath中,因爲persistent目錄是在運行過一次才創建的。
這樣,之後再更新資源就直接下載到persistent目錄下了
但是,WebGL項目呢
這個就不存在什麼streaming或者persistent了,因爲不能加載本地路徑
所以就只有緩存,加載包時就要用
WWW.LoadFromDownloadOrCache(url, version)
這樣會把資源下載到緩存目錄中,每次加載時會判斷版本,相同則直接從本地磁盤加載,不然才從網絡下載,更新本地磁盤中的緩存。
這裏坑就來了,就是這個版本號。第一次加載還好,隨便設置個數,因爲本地沒有麼,直接下載了。以後呢,怎麼判斷本地的版本和服務器的版本呢?
之所以有這個問題,是因爲這個版本號是加載時寫在程序裏的,比如說第一次下載後,會把各包加載時的這個版本號也記錄在本地緩存裏,下次再加載時,程序裏設置的版本號會與本地緩存中之前記錄的版本號對比,如果不同,則說明有更新,下載包覆蓋本地緩存,再加載,如果一樣則沒有更新,不下載,直接加載本地緩存。
看了很多例子,都是簡單的寫個0或者1,哪怕服務器端資源更新了,如果這個版本號還是用的和上次一樣的,就認爲沒有更新,也不會從網絡下載。
那麼得想辦法動態的獲取包的這個版本,那麼
WWW.LoadFromDownloadOrCache(url, version)
這個重載方法就不合適了,因爲這個version沒找到辦法獲取……
文檔裏說的是這個version要自增,也就是新的version要大於老的才更新,不過看網上有人說只要版本號不同,就更新,無論是大於還是小於,這個沒試過,不過也無所謂了。
看了一眼,這個加載方法的另一項重載是:
public static WWW LoadFromCacheOrDownload(string url, Hash128 hash, uint crc);
說明:以下只是目前的一個設想,沒有實踐
首先說最後一個參數crc,按文檔裏說的,這個值非0時則對比crc,目前不關心這個,就讓它是0
最重要的就是第二個參數hash
文檔解釋:
hash Hash128 which is used as the version of the AssetBundle.
對比這個可以相當於version版本。
那好,想辦法得到各assetbundle包的Hash128
從manifest文件下手,打包之後會有個總的manifest文件,和你的包的根目錄名同名
比如打包在StreamingAssets下,則其目錄下有一個StreamingAssets.manifest文件
using(WWW www=WWW.LoadFromDownloadOrCache("..../StreamingAssets/StreamingAssets"))
{
yield return www;
AssetBundle ab=www.assetBundle;
AssetBundleManifest abm=ab.loadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] bundleNames=abm.GetAllAssetBundles();
foreach(string item in bundleNames)
{
Hash128 hash = abm.GetAssetBundleHash(item);
}
}
如上,GetAllAssetBundles()可以得到所有包的包名
再用GetAssetBundleHash(包名)得到包對應的hash128
那麼每次加載資源之前,先把包的Hash128獲取到,再用
public static WWW LoadFromCacheOrDownload(string url, Hash128 hash, uint crc);
這樣每次加載都會對比這個Hash128值,這個就相當於是版本了
我試了一下,在開發環境下,如果資源沒有任何修改,反覆打包,出來的這個Hash128是不變的,如果有修改,比如材質的顏色變化一下,prefab的scale變化一下之類的,再打出來的包,Hash128就變化了。
理論上說,這樣LoadFromDownloadOrCache就可以判斷出有沒有更新了
所以,每次打開程序,首先加載總的manifest,把包和對應的Hash128存到一個地方,比如字典
Dictionary<string, Hash128> bundleHashDict = new Dictionary<string, Hash128>();
using(WWW www=WWW.LoadFromDownloadOrCache("..../StreamingAssets/StreamingAssets"))
{
yield return www;
AssetBundle ab=www.assetBundle;
AssetBundleManifest abm=ab.loadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] bundleNames=abm.GetAllAssetBundles();
foreach(string item in bundleNames)
{
Hash128 hash = abm.GetAssetBundleHash(item);
bundleHashDict.Add(item, hash);
}
}
要加載一個名叫“a.assetbundle"的包
string path = "...../a.assetbundle";
Hash128 hash=bundleHashDict["a.assetbundle"];
using(WWW www = WWW.LoadFromDownloadOrCache(path, hash, 0))
{
yield return www;
.........
}
如上,根據包名在字典裏取得其之前獲取並存入字典裏的Hash128,作爲LoadFromDownloadOrCache方法的第二個參數,理論上會與本地緩存最後一次更新下載時存儲的包的Hash128(在上一次調用此方法時寫入緩存的)進行對比,相同則不更新,不同則更新。
理論上如此,有待實踐