question

bellealmoraat avatar image
bellealmoraat asked

Failing to unpack Unity AssetBundle downloaded from CDN

Hi there, I am trying to build a relatively simple DLC content system with PlayFab. I have a problem with the downloaded file, however, getting error "Error while downloading Asset Bundle: Failed to decompress data for the AssetBundle".

After debugging it looks like the logic is getting the URL correctly, the downloading itself is successful and in the request object, there is seemingly the correct amount of bytes received. The moment I get to the point of retrieving the assetBundle object I get the error above and the bundle itself is null.

Interestingly enough, if I use the URL provided by the PlayFab API in a browser, the file I download is successfully loaded via AssetBundle.LoadFromFileAsync test call. So, the binary format seems to be intact.

I am not sure what I am missing at this point. Any help or suggestion will be much appreciated. Here is the simple code I am using to download the bundle:

public void RetrieveAssetBundle( string dlcPath, string dlcName, string dlcHash, OnAssetBundleRetrieved onAssetBundleRetrieved ) {
	this.onAssetBundleRetrieved = onAssetBundleRetrieved;
	
	PlayFabClientAPI.GetContentDownloadUrl(
		new GetContentDownloadUrlRequest() {
			Key = dlcPath + dlcName,
			ThruCDN = false // TODO: set this to true in production
		}, 
		( GetContentDownloadUrlResult result ) => StartCoroutine( DownloadFromCDN( result.URL, dlcName, dlcHash ) ),
		( PlayFabError error ) => Debug.LogError( "RetrieveAssetBundle Error: " + error.ErrorMessage )
	);
}

private IEnumerator DownloadFromCDN( string cdnDownloadURL, string dlcName, string dlcHash ) {
	Debug.Log( "PlayFab download URL: " + cdnDownloadURL );

	using ( UnityWebRequest request = UnityWebRequest.GetAssetBundle( cdnDownloadURL, new CachedAssetBundle() {
		hash = Hash128.Parse( dlcHash ),
		name = downloadedAssetBundlesPath + dlcName
	}, 0 ) ) {
		yield return request.SendWebRequest();

		if ( request.isNetworkError || request.isHttpError ) {
			Debug.LogError( "DownloadFromCDN Error: " + request.error );
		} else {
			AssetBundle bundle = DownloadHandlerAssetBundle.GetContent( request );
			if ( onAssetBundleRetrieved != null ) {
				onAssetBundleRetrieved( bundle );
			}
		}
	}
}
Content
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

marcowilliamspf avatar image
marcowilliamspf answered

Hi,

I have not messed with asset bundles in a while, nearly a year. I had created this little repository sample of using the Asset Bundle manager with our service. This was before UnityWebRequest and it has not been tested on anything remotely near 2017.x or 2018.x, however you might want to take a look at what I was doing with it, as it might give you some clue.

From my perspective, you seem to be doing all the right stuff in your code above. However, it looks like your taking the asset bundle and passing it to a callback "onAssetBundleRetrieved" .. I wasn't doing that. I went about loading the asset bundles a different way.

 // Load asset from assetBundle.
        AssetBundleLoadAssetOperation request = AssetBundleManager.LoadAssetAsync(bundleName, assetName, typeof(GameObject), urlParams);

Now I'm not even sure if this is the right way to do it anymore, but it might be worth a look.

Another thing to note is the mime-type of the asset when you uploaded it to the CDN. If you do not specify that it is a application/binary, when it downloads from the CDN it might pass with the headers the wrong mime-type with delivery which could mess things up.

sorry I could not be more help here.

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

bellealmoraat avatar image bellealmoraat commented ·

Thanks for the link, it will certainly help with insights when I try to expand my humble manager to cover more use cases.

For now, things seem to function well enough if I am not attempting to use a custom cache path. Unfortunately, the documentation in Unity API is not complete on that particular topic, so I'll park it for the time being and return to it when I start polishing the game. If I find a solution for it, I'll post it here in case someone else hits that particular wall in the future. :)

0 Likes 0 ·
1807605288 avatar image
1807605288 answered

The next thing I would try is saving the file in Unity to the hard disk, and binary-comparing against the one received from the browser.

From your description of the problem, I don't really have any obvious answers for you.

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

bellealmoraat avatar image bellealmoraat commented ·

I tried as you suggested and the files are identical. After that, I managed to make it work using the hash only instead of the CachedAssetBundle object. It looks like the issue is with that particular class in Unity's framework, but so far I haven't been able to identify what exactly fails there. So, essentially changing the web request to:

UnityWebRequest.GetAssetBundle( cdnDownloadURL, Hash128.Parse( dlcHash ), dlcCRC )

is enough to make the code above functional.

Unfortunately, this means I will be stuck for the time being with Unity's default cache folder.

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.