- Home /
Check whether a assetbundle has been already downloaded
Is there a way to know whether an asset bundle is already downloaded and stored in the cache?
Unity already provides a method to either download or load from cache with WWW.LoadFromCacheOrDownload, so at least internally, they know what's the state of the asset bundle.
However, I can't find a way to ask Unity whether my asset bundle is already downloaded so I don't go through the trouble or trying to download it again.
Currently I show a progress bar to the player every time because I don't know what's downloaded or not.
Thank you for the answer pitmoi! That free me from a big code implementation already addressed by the Unity $$anonymous$$m.
I have a query though, are you checking for new file versions? If that is the case, then in your manual version system what is the way in which you are checking the server file to get the new version?
Hi Lermy, I answered this point in details in this thread : issues-with-wwwloadfromcacheordownload
But a quick summary is : update your assetbundle version in a json file on the server, check it first when the game start, and if the version number on the server differs from the one in your saved game (you will have to save it manually, using playerpref for example) re-download the new version of the assetbundle.
Answer by pitimoi · Aug 14, 2013 at 04:35 PM
Hi,
You have to save the current downloaded version of your assetbundle on your side because Unity doesn't offer any solution for version tracking, except when calling WWW.LoadFromCacheOrDownload...
Update your saved number, call WWW.LoadFromCacheOrDownload and show a progress bar to the player only if your bundle version changed.
I generally keep an xml file server-side to read all existing assetbundle in my game and their current server version, I compare it to my current saved data and download any update or new assetbundle the player may need to play.
O$$anonymous$$, I have a version number tied to my assets on the server side and the file name contains that number as well. So I can parse the version number from the downloaded file and check against my server. How do I download an asset bundle to a specific location though? Thanks.
In my case, I have an editor script that generates my assetbundles and creates my xml bundle config file I upload to the server. It looks something like that :
<?xml version="1.0" encoding="utf-8"?>
<root>
<bundle path="Test.assetbundle" version="1" />
</root>
Then, I have the path to my server folder where I store all my bundles and this xml file. When the game start, I open the xml with
WWW www = new WWW(_ServerPath+"/"+_XmlName);
and retreive the xml infos from www.text
Finally, just parse your data to know all your assetbundle name and their current version.
The X$$anonymous$$L idea sounds great. I'll try that. Thank you!
So, how do you load your downloaded assetbundle? I'm trying to load it like so: new WWW("file://" + Application.temporaryCachePath + "/" + file) and I'm getting the error: Couldn't open file /Users/....... Could you help? Thanks. It save's it fine at that location when I do File.WriteAllBytes(Application.temporaryCachePath + "/" + file, bytes);
No, I always open my assetbundle with WWW.LoadFromCacheOrDownload because my test with the xml file assure me that the bundle is up to date for the current player session, and then, WWW.LoadFromCacheOrDownload will always load bundle from cache during the game. The new WWW I use is only to read the server xml bundle configuration I compare with my local saved version.
For information, when you try to reach a folder with WWW, use "file:///" with 3 / or it will always fail.
Answer by lermy3d · Jul 08, 2015 at 09:08 AM
You can also ask this method Caching.IsVersionCached if the bundle has been loaded. You will need to specify the url path to the bundle and the version of the bundle itself.
I don't know why this method does not have an overloaded function where you can pass a hash crc of the bundle like in WWW.LoadFromCacheOrDownload.
This would solve many asset management issues for developers, for instance I could calculate if the free space in the cache is enough for downloading the bundle, if not I could otherwise download it using the www non caching method and then just asking for www.assetBundle.
The description for Caching.IsVersionCached can be found in unity's documentation here.
Hi Lermy,
This new function should be the one used to see if the assetbundle is in cache and you are right on this point. But you don't have to call a new WWW() yourself if you don't have enough space on your disk, the documentation on the WWW.LoadFromCacheOrDownload says :
If the cache folder does not have any space for caching additional files, LoadFromCacheOrDownload will iteratively delete the least-recently-used AssetBundles from the Cache until sufficient space is available to store the new AssetBundle. If making space is not possible (because the hard disk is full, or all files in the cache are currently in use), LoadFromCacheOrDownload() will bypass Caching and stream the file into memory like a normal "new WWW()" call.
Which is nice, but I feel it really dangerous if you want to access your assetbundle when the player is offline, because you have no control of what is in the cache or not.
I never use assetbundle directly from a remote path on my project. I always prefer a solution using new WWW() to download the assetbundle into the Application.persistantDataPath and then open them from this place. With such method, I am in full control of what is downloaded, what will be deleted from the disk at each update and what is the available size on the disk in order to download a new assetbundle.
Thank you for the answer pitimoi! That free me from a big code implementation already addressed by the Unity $$anonymous$$m.
I have a query though, are you checking for new file versions? If that is the case then in your manual version system what is the way in which you are checking the server file for a new version?
I answered this point in the comments on my own answer, let me know if you want/need more details :)
Yes well, probably I did not ask it correctly so let me use an example.
Let's say that you have a new version of the bundle on the server, and you already have that bundle downloaded previously on the client side, now how can you know that the server the file is new or otherwise use the cached version if you are not using LoadFromCacheOrDownload? since with that function is the one that you can pass a hash crc of the bundle for comparison.
In fact, I'm not using crc because WWW can't do it. So, what I do there is :
1 - I build my assetbundle and create a json file (or xml or whatever...) which contains for each assetbundle the version number and a md5 hash its binary.
2 - When the player launch the game, I get the json from the server and compare the version number between the player saved game and the server current value. If it is the same, I check the md5 hash (just to be sure it is nor corrupted).
3 - Is the version from the server is newer or the md5 hash differs, I download the package from the server and save it as the new version.
4 - When everything is done, the player got a download version of each assetbundle and a file (json, xml, encrypted binary...) which contains the current version of each assetbundle in its saved game directory.
Answer by studentutu · Nov 23, 2018 at 02:17 PM
@pekalicious, @pitimoi, @lermy3d Just to keep this alive ( first thing that on Google ) : From unity 2017 and onwards (not sure about earlier versions) we have Caching (https://docs.unity3d.com/ScriptReference/Caching.html).
And you can use something like this to view if the Asset Bundle is in Cache (tested on IOS, Android, Editor):
private bool checkForCachedBigData(string urlToCheck = null)
{
var allHashes = new List<Hash128>();
bool found = false;
string pathInStorage = "LanguageListing/";
#if UNITY_ANDROID
pathInStorage += "Android/bigdataobject";
Caching.GetCachedVersions(pathInStorage, allHashes);
#endif
#if UNITY_IOS
pathInStorage += "IOS/bigdataobject";
Caching.GetCachedVersions(pathInStorage,allHashes );
#endif
foreach (var item in allHashes)
{
if (!Caching.IsVersionCached(urlToCheck, item)) continue;
Debug.Log("Found in Cache: " + pathInStorage);
found = true;
}
// will onlu be true only if one version is cached
return found && allHashes.Count < 2;
}
Also, you can use something like this (tested inside the Editor):
public bool IsBundleCached(string bundleName)
{
List<string> allCachedPath = new List<string>();
Caching.GetAllCachePaths(allCachedPath);
var path = allCachedPath[0];
System.IO.DirectoryInfo someIbfo = new System.IO.DirectoryInfo(path);
var allDirectoriesInside = someIbfo.GetDirectories();
var allFilesInside = someIbfo.GetFiles();
bool exists = false;
var allDirectoriesInsideFodler = someIbfo;
var allDirectoriesInside2 = allDirectoriesInside;
var allFilesInsideFolders = someIbfo.GetFiles();
foreach (var item in allDirectoriesInside)
{
// Works for Editor
if (item.FullName.Contains(bundleName.ToLower()))
{
exists = true;
}
}
foreach (var item in allFilesInside)
{
if (item.FullName.Contains(bundleName.ToLower()))
{
exists = true;
}
}
return exists;
}